drm: omapdrm: gem: Remove check for impossible condition
[deliverable/linux.git] / drivers / gpu / drm / omapdrm / tcm-sita.c
CommitLineData
71e8831f
AG
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 */
28static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL;
29static s32 CR_R2L_T2B = CR_DIAGONAL_BALANCE;
30
31/*********************************************
32 * TCM API - Sita Implementation
33 *********************************************/
34static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
35 struct tcm_area *area);
36static s32 sita_reserve_1d(struct tcm *tcm, u32 slots, struct tcm_area *area);
37static s32 sita_free(struct tcm *tcm, struct tcm_area *area);
38static void sita_deinit(struct tcm *tcm);
39
40/*********************************************
41 * Main Scanner functions
42 *********************************************/
43static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
44 struct tcm_area *area);
45
46static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
47 struct tcm_area *field, struct tcm_area *area);
48
49static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
50 struct tcm_area *field, struct tcm_area *area);
51
52static 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 *********************************************/
58static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
59
60static 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
64static void get_nearness_factor(struct tcm_area *field,
65 struct tcm_area *candidate,
66 struct nearness_factor *nf);
67
68static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
69 struct neighbor_stats *stat);
70
71static void fill_area(struct tcm *tcm,
72 struct tcm_area *area, struct tcm_area *parent);
73
74
75/*********************************************/
76
77/*********************************************
78 * Utility Methods
79 *********************************************/
80struct 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
07a6dc19
RV
90 tcm = kzalloc(sizeof(*tcm), GFP_KERNEL);
91 pvt = kzalloc(sizeof(*pvt), GFP_KERNEL);
71e8831f
AG
92 if (!tcm || !pvt)
93 goto error;
94
71e8831f
AG
95 /* Updating the pointers to SiTA implementation APIs */
96 tcm->height = height;
97 tcm->width = width;
98 tcm->reserve_2d = sita_reserve_2d;
99 tcm->reserve_1d = sita_reserve_1d;
100 tcm->free = sita_free;
101 tcm->deinit = sita_deinit;
102 tcm->pvt = (void *)pvt;
103
104 spin_lock_init(&(pvt->lock));
105
106 /* Creating tam map */
107 pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
108 if (!pvt->map)
109 goto error;
110
111 for (i = 0; i < tcm->width; i++) {
112 pvt->map[i] =
113 kmalloc(sizeof(**pvt->map) * tcm->height,
114 GFP_KERNEL);
115 if (pvt->map[i] == NULL) {
116 while (i--)
117 kfree(pvt->map[i]);
118 kfree(pvt->map);
119 goto error;
120 }
121 }
122
123 if (attr && attr->x <= tcm->width && attr->y <= tcm->height) {
124 pvt->div_pt.x = attr->x;
125 pvt->div_pt.y = attr->y;
126
127 } else {
128 /* Defaulting to 3:1 ratio on width for 2D area split */
129 /* Defaulting to 3:1 ratio on height for 2D and 1D split */
130 pvt->div_pt.x = (tcm->width * 3) / 4;
131 pvt->div_pt.y = (tcm->height * 3) / 4;
132 }
133
134 spin_lock(&(pvt->lock));
135 assign(&area, 0, 0, width - 1, height - 1);
136 fill_area(tcm, &area, NULL);
137 spin_unlock(&(pvt->lock));
138 return tcm;
139
140error:
141 kfree(tcm);
142 kfree(pvt);
143 return NULL;
144}
145
146static void sita_deinit(struct tcm *tcm)
147{
148 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
149 struct tcm_area area = {0};
150 s32 i;
151
152 area.p1.x = tcm->width - 1;
153 area.p1.y = tcm->height - 1;
154
155 spin_lock(&(pvt->lock));
156 fill_area(tcm, &area, NULL);
157 spin_unlock(&(pvt->lock));
158
159 for (i = 0; i < tcm->height; i++)
160 kfree(pvt->map[i]);
161 kfree(pvt->map);
162 kfree(pvt);
163}
164
165/**
166 * Reserve a 1D area in the container
167 *
168 * @param num_slots size of 1D area
169 * @param area pointer to the area that will be populated with the
170 * reserved area
171 *
172 * @return 0 on success, non-0 error value on failure.
173 */
174static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
175 struct tcm_area *area)
176{
177 s32 ret;
178 struct tcm_area field = {0};
179 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
180
181 spin_lock(&(pvt->lock));
182
183 /* Scanning entire container */
184 assign(&field, tcm->width - 1, tcm->height - 1, 0, 0);
185
186 ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area);
187 if (!ret)
188 /* update map */
189 fill_area(tcm, area, area);
190
191 spin_unlock(&(pvt->lock));
192 return ret;
193}
194
195/**
196 * Reserve a 2D area in the container
197 *
198 * @param w width
199 * @param h height
6354eb81 200 * @param area pointer to the area that will be populated with the reserved
71e8831f
AG
201 * area
202 *
203 * @return 0 on success, non-0 error value on failure.
204 */
205static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
206 struct tcm_area *area)
207{
208 s32 ret;
209 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
210
211 /* not supporting more than 64 as alignment */
212 if (align > 64)
213 return -EINVAL;
214
215 /* we prefer 1, 32 and 64 as alignment */
216 align = align <= 1 ? 1 : align <= 32 ? 32 : 64;
217
218 spin_lock(&(pvt->lock));
219 ret = scan_areas_and_find_fit(tcm, w, h, align, area);
220 if (!ret)
221 /* update map */
222 fill_area(tcm, area, area);
223
224 spin_unlock(&(pvt->lock));
225 return ret;
226}
227
228/**
229 * Unreserve a previously allocated 2D or 1D area
230 * @param area area to be freed
231 * @return 0 - success
232 */
233static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
234{
235 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
236
237 spin_lock(&(pvt->lock));
238
239 /* check that this is in fact an existing area */
240 WARN_ON(pvt->map[area->p0.x][area->p0.y] != area ||
241 pvt->map[area->p1.x][area->p1.y] != area);
242
243 /* Clear the contents of the associated tiles in the map */
244 fill_area(tcm, area, NULL);
245
246 spin_unlock(&(pvt->lock));
247
248 return 0;
249}
250
251/**
252 * Note: In general the cordinates in the scan field area relevant to the can
253 * sweep directions. The scan origin (e.g. top-left corner) will always be
254 * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x
255 * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y
256 * <= p0.y
257 */
258
259/**
260 * Raster scan horizontally right to left from top to bottom to find a place for
261 * a 2D area of given size inside a scan field.
262 *
263 * @param w width of desired area
264 * @param h height of desired area
265 * @param align desired area alignment
266 * @param area pointer to the area that will be set to the best position
267 * @param field area to scan (inclusive)
268 *
269 * @return 0 on success, non-0 error value on failure.
270 */
271static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
272 struct tcm_area *field, struct tcm_area *area)
273{
274 s32 x, y;
275 s16 start_x, end_x, start_y, end_y, found_x = -1;
276 struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
277 struct score best = {{0}, {0}, {0}, 0};
278
279 start_x = field->p0.x;
280 end_x = field->p1.x;
281 start_y = field->p0.y;
282 end_y = field->p1.y;
283
284 /* check scan area co-ordinates */
285 if (field->p0.x < field->p1.x ||
286 field->p1.y < field->p0.y)
287 return -EINVAL;
288
289 /* check if allocation would fit in scan area */
290 if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y))
291 return -ENOSPC;
292
293 /* adjust start_x and end_y, as allocation would not fit beyond */
294 start_x = ALIGN_DOWN(start_x - w + 1, align); /* - 1 to be inclusive */
295 end_y = end_y - h + 1;
296
297 /* check if allocation would still fit in scan area */
298 if (start_x < end_x)
299 return -ENOSPC;
300
301 /* scan field top-to-bottom, right-to-left */
302 for (y = start_y; y <= end_y; y++) {
303 for (x = start_x; x >= end_x; x -= align) {
304 if (is_area_free(map, x, y, w, h)) {
305 found_x = x;
306
307 /* update best candidate */
308 if (update_candidate(tcm, x, y, w, h, field,
309 CR_R2L_T2B, &best))
310 goto done;
311
312 /* change upper x bound */
313 end_x = x + 1;
314 break;
315 } else if (map[x][y] && map[x][y]->is2d) {
316 /* step over 2D areas */
317 x = ALIGN(map[x][y]->p0.x - w + 1, align);
318 }
319 }
320
321 /* break if you find a free area shouldering the scan field */
322 if (found_x == start_x)
323 break;
324 }
325
326 if (!best.a.tcm)
327 return -ENOSPC;
328done:
329 assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
330 return 0;
331}
332
333/**
334 * Raster scan horizontally left to right from top to bottom to find a place for
335 * a 2D area of given size inside a scan field.
336 *
337 * @param w width of desired area
338 * @param h height of desired area
339 * @param align desired area alignment
340 * @param area pointer to the area that will be set to the best position
341 * @param field area to scan (inclusive)
342 *
343 * @return 0 on success, non-0 error value on failure.
344 */
345static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
346 struct tcm_area *field, struct tcm_area *area)
347{
348 s32 x, y;
349 s16 start_x, end_x, start_y, end_y, found_x = -1;
350 struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
351 struct score best = {{0}, {0}, {0}, 0};
352
353 start_x = field->p0.x;
354 end_x = field->p1.x;
355 start_y = field->p0.y;
356 end_y = field->p1.y;
357
358 /* check scan area co-ordinates */
359 if (field->p1.x < field->p0.x ||
360 field->p1.y < field->p0.y)
361 return -EINVAL;
362
363 /* check if allocation would fit in scan area */
364 if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
365 return -ENOSPC;
366
367 start_x = ALIGN(start_x, align);
368
369 /* check if allocation would still fit in scan area */
370 if (w > LEN(end_x, start_x))
371 return -ENOSPC;
372
373 /* adjust end_x and end_y, as allocation would not fit beyond */
374 end_x = end_x - w + 1; /* + 1 to be inclusive */
375 end_y = end_y - h + 1;
376
377 /* scan field top-to-bottom, left-to-right */
378 for (y = start_y; y <= end_y; y++) {
379 for (x = start_x; x <= end_x; x += align) {
380 if (is_area_free(map, x, y, w, h)) {
381 found_x = x;
382
383 /* update best candidate */
384 if (update_candidate(tcm, x, y, w, h, field,
385 CR_L2R_T2B, &best))
386 goto done;
387 /* change upper x bound */
388 end_x = x - 1;
389
390 break;
391 } else if (map[x][y] && map[x][y]->is2d) {
392 /* step over 2D areas */
393 x = ALIGN_DOWN(map[x][y]->p1.x, align);
394 }
395 }
396
397 /* break if you find a free area shouldering the scan field */
398 if (found_x == start_x)
399 break;
400 }
401
402 if (!best.a.tcm)
403 return -ENOSPC;
404done:
405 assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
406 return 0;
407}
408
409/**
410 * Raster scan horizontally right to left from bottom to top to find a place
411 * for a 1D area of given size inside a scan field.
412 *
413 * @param num_slots size of desired area
414 * @param align desired area alignment
415 * @param area pointer to the area that will be set to the best
416 * position
417 * @param field area to scan (inclusive)
418 *
419 * @return 0 on success, non-0 error value on failure.
420 */
421static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
422 struct tcm_area *field, struct tcm_area *area)
423{
424 s32 found = 0;
425 s16 x, y;
426 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
427 struct tcm_area *p;
428
429 /* check scan area co-ordinates */
430 if (field->p0.y < field->p1.y)
431 return -EINVAL;
432
433 /**
434 * Currently we only support full width 1D scan field, which makes sense
435 * since 1D slot-ordering spans the full container width.
436 */
437 if (tcm->width != field->p0.x - field->p1.x + 1)
438 return -EINVAL;
439
440 /* check if allocation would fit in scan area */
441 if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y))
442 return -ENOSPC;
443
444 x = field->p0.x;
445 y = field->p0.y;
446
447 /* find num_slots consecutive free slots to the left */
448 while (found < num_slots) {
449 if (y < 0)
450 return -ENOSPC;
451
452 /* remember bottom-right corner */
453 if (found == 0) {
454 area->p1.x = x;
455 area->p1.y = y;
456 }
457
458 /* skip busy regions */
459 p = pvt->map[x][y];
460 if (p) {
461 /* move to left of 2D areas, top left of 1D */
462 x = p->p0.x;
463 if (!p->is2d)
464 y = p->p0.y;
465
466 /* start over */
467 found = 0;
468 } else {
469 /* count consecutive free slots */
470 found++;
471 if (found == num_slots)
472 break;
473 }
474
475 /* move to the left */
476 if (x == 0)
477 y--;
478 x = (x ? : tcm->width) - 1;
479
480 }
481
482 /* set top-left corner */
483 area->p0.x = x;
484 area->p0.y = y;
485 return 0;
486}
487
488/**
489 * Find a place for a 2D area of given size inside a scan field based on its
490 * alignment needs.
491 *
492 * @param w width of desired area
493 * @param h height of desired area
494 * @param align desired area alignment
495 * @param area pointer to the area that will be set to the best position
496 *
497 * @return 0 on success, non-0 error value on failure.
498 */
499static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
500 struct tcm_area *area)
501{
502 s32 ret = 0;
503 struct tcm_area field = {0};
504 u16 boundary_x, boundary_y;
505 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
506
507 if (align > 1) {
508 /* prefer top-left corner */
509 boundary_x = pvt->div_pt.x - 1;
510 boundary_y = pvt->div_pt.y - 1;
511
512 /* expand width and height if needed */
513 if (w > pvt->div_pt.x)
514 boundary_x = tcm->width - 1;
515 if (h > pvt->div_pt.y)
516 boundary_y = tcm->height - 1;
517
518 assign(&field, 0, 0, boundary_x, boundary_y);
519 ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
520
521 /* scan whole container if failed, but do not scan 2x */
522 if (ret != 0 && (boundary_x != tcm->width - 1 ||
523 boundary_y != tcm->height - 1)) {
524 /* scan the entire container if nothing found */
525 assign(&field, 0, 0, tcm->width - 1, tcm->height - 1);
526 ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
527 }
528 } else if (align == 1) {
529 /* prefer top-right corner */
530 boundary_x = pvt->div_pt.x;
531 boundary_y = pvt->div_pt.y - 1;
532
533 /* expand width and height if needed */
534 if (w > (tcm->width - pvt->div_pt.x))
535 boundary_x = 0;
536 if (h > pvt->div_pt.y)
537 boundary_y = tcm->height - 1;
538
539 assign(&field, tcm->width - 1, 0, boundary_x, boundary_y);
540 ret = scan_r2l_t2b(tcm, w, h, align, &field, area);
541
542 /* scan whole container if failed, but do not scan 2x */
543 if (ret != 0 && (boundary_x != 0 ||
544 boundary_y != tcm->height - 1)) {
545 /* scan the entire container if nothing found */
546 assign(&field, tcm->width - 1, 0, 0, tcm->height - 1);
547 ret = scan_r2l_t2b(tcm, w, h, align, &field,
548 area);
549 }
550 }
551
552 return ret;
553}
554
555/* check if an entire area is free */
556static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h)
557{
558 u16 x = 0, y = 0;
559 for (y = y0; y < y0 + h; y++) {
560 for (x = x0; x < x0 + w; x++) {
561 if (map[x][y])
562 return false;
563 }
564 }
565 return true;
566}
567
568/* fills an area with a parent tcm_area */
569static void fill_area(struct tcm *tcm, struct tcm_area *area,
570 struct tcm_area *parent)
571{
572 s32 x, y;
573 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
574 struct tcm_area a, a_;
575
576 /* set area's tcm; otherwise, enumerator considers it invalid */
577 area->tcm = tcm;
578
579 tcm_for_each_slice(a, *area, a_) {
580 for (x = a.p0.x; x <= a.p1.x; ++x)
581 for (y = a.p0.y; y <= a.p1.y; ++y)
582 pvt->map[x][y] = parent;
583
584 }
585}
586
587/**
588 * Compares a candidate area to the current best area, and if it is a better
589 * fit, it updates the best to this one.
590 *
591 * @param x0, y0, w, h top, left, width, height of candidate area
592 * @param field scan field
593 * @param criteria scan criteria
594 * @param best best candidate and its scores
595 *
596 * @return 1 (true) if the candidate area is known to be the final best, so no
597 * more searching should be performed
598 */
599static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
600 struct tcm_area *field, s32 criteria,
601 struct score *best)
602{
603 struct score me; /* score for area */
604
605 /*
606 * NOTE: For horizontal bias we always give the first found, because our
607 * scan is horizontal-raster-based and the first candidate will always
608 * have the horizontal bias.
609 */
610 bool first = criteria & CR_BIAS_HORIZONTAL;
611
612 assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1);
613
614 /* calculate score for current candidate */
615 if (!first) {
616 get_neighbor_stats(tcm, &me.a, &me.n);
617 me.neighs = me.n.edge + me.n.busy;
618 get_nearness_factor(field, &me.a, &me.f);
619 }
620
621 /* the 1st candidate is always the best */
622 if (!best->a.tcm)
623 goto better;
624
625 BUG_ON(first);
626
627 /* diagonal balance check */
628 if ((criteria & CR_DIAGONAL_BALANCE) &&
629 best->neighs <= me.neighs &&
630 (best->neighs < me.neighs ||
631 /* this implies that neighs and occupied match */
632 best->n.busy < me.n.busy ||
633 (best->n.busy == me.n.busy &&
634 /* check the nearness factor */
635 best->f.x + best->f.y > me.f.x + me.f.y)))
636 goto better;
637
638 /* not better, keep going */
639 return 0;
640
641better:
642 /* save current area as best */
643 memcpy(best, &me, sizeof(me));
644 best->a.tcm = tcm;
645 return first;
646}
647
648/**
649 * Calculate the nearness factor of an area in a search field. The nearness
650 * factor is smaller if the area is closer to the search origin.
651 */
652static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area,
653 struct nearness_factor *nf)
654{
655 /**
656 * Using signed math as field coordinates may be reversed if
657 * search direction is right-to-left or bottom-to-top.
658 */
659 nf->x = (s32)(area->p0.x - field->p0.x) * 1000 /
660 (field->p1.x - field->p0.x);
661 nf->y = (s32)(area->p0.y - field->p0.y) * 1000 /
662 (field->p1.y - field->p0.y);
663}
664
665/* get neighbor statistics */
666static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
667 struct neighbor_stats *stat)
668{
669 s16 x = 0, y = 0;
670 struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
671
672 /* Clearing any exisiting values */
673 memset(stat, 0, sizeof(*stat));
674
675 /* process top & bottom edges */
676 for (x = area->p0.x; x <= area->p1.x; x++) {
677 if (area->p0.y == 0)
678 stat->edge++;
679 else if (pvt->map[x][area->p0.y - 1])
680 stat->busy++;
681
682 if (area->p1.y == tcm->height - 1)
683 stat->edge++;
684 else if (pvt->map[x][area->p1.y + 1])
685 stat->busy++;
686 }
687
688 /* process left & right edges */
689 for (y = area->p0.y; y <= area->p1.y; ++y) {
690 if (area->p0.x == 0)
691 stat->edge++;
692 else if (pvt->map[area->p0.x - 1][y])
693 stat->busy++;
694
695 if (area->p1.x == tcm->width - 1)
696 stat->edge++;
697 else if (pvt->map[area->p1.x + 1][y])
698 stat->busy++;
699 }
700}
This page took 0.260237 seconds and 5 git commands to generate.