Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/omap: Use bitmaps for TILER placement

Modified Tiler placement to utilize bitmaps for bookkeeping and
all placement algorithms. This resulted in a substantial savings
in time for all Tiler reservation and free operations. Typical
savings are in the range of 28% decrease in time taken with larger
buffers showing a 80%+ decrease.

Signed-off-by: Andy Gross <andy.gross@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>

authored by

Andy Gross and committed by
Tomi Valkeinen
0d6fa53f 73d77107

+225 -658
+8 -6
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
··· 363 363 u32 min_align = 128; 364 364 int ret; 365 365 unsigned long flags; 366 + size_t slot_bytes; 366 367 367 368 BUG_ON(!validfmt(fmt)); 368 369 ··· 372 371 h = DIV_ROUND_UP(h, geom[fmt].slot_h); 373 372 374 373 /* convert alignment to slots */ 375 - min_align = max(min_align, (geom[fmt].slot_w * geom[fmt].cpp)); 376 - align = ALIGN(align, min_align); 377 - align /= geom[fmt].slot_w * geom[fmt].cpp; 374 + slot_bytes = geom[fmt].slot_w * geom[fmt].cpp; 375 + min_align = max(min_align, slot_bytes); 376 + align = (align > min_align) ? ALIGN(align, min_align) : min_align; 377 + align /= slot_bytes; 378 378 379 379 block->fmt = fmt; 380 380 381 - ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area); 381 + ret = tcm_reserve_2d(containers[fmt], w, h, align, -1, slot_bytes, 382 + &block->area); 382 383 if (ret) { 383 384 kfree(block); 384 385 return ERR_PTR(-ENOMEM); ··· 742 739 programming during reill operations */ 743 740 for (i = 0; i < omap_dmm->num_lut; i++) { 744 741 omap_dmm->tcm[i] = sita_init(omap_dmm->container_width, 745 - omap_dmm->container_height, 746 - NULL); 742 + omap_dmm->container_height); 747 743 748 744 if (!omap_dmm->tcm[i]) { 749 745 dev_err(&dev->dev, "failed to allocate container\n");
+202 -641
drivers/gpu/drm/omapdrm/tcm-sita.c
··· 5 5 * 6 6 * Authors: Ravi Ramachandra <r.ramachandra@ti.com>, 7 7 * Lajos Molnar <molnar@ti.com> 8 + * Andy Gross <andy.gross@ti.com> 8 9 * 9 - * Copyright (C) 2009-2010 Texas Instruments, Inc. 10 + * Copyright (C) 2012 Texas Instruments, Inc. 10 11 * 11 12 * This package is free software; you can redistribute it and/or modify 12 13 * it under the terms of the GNU General Public License version 2 as ··· 18 17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 18 * 20 19 */ 20 + #include <linux/init.h> 21 + #include <linux/module.h> 22 + #include <linux/errno.h> 23 + #include <linux/sched.h> 24 + #include <linux/wait.h> 25 + #include <linux/bitmap.h> 21 26 #include <linux/slab.h> 22 - #include <linux/spinlock.h> 27 + #include "tcm.h" 23 28 24 - #include "tcm-sita.h" 29 + static unsigned long mask[8]; 30 + /* 31 + * pos position in bitmap 32 + * w width in slots 33 + * h height in slots 34 + * map ptr to bitmap 35 + * stride slots in a row 36 + */ 37 + static void free_slots(unsigned long pos, uint16_t w, uint16_t h, 38 + unsigned long *map, uint16_t stride) 39 + { 40 + int i; 25 41 26 - #define ALIGN_DOWN(value, align) ((value) & ~((align) - 1)) 42 + for (i = 0; i < h; i++, pos += stride) 43 + bitmap_clear(map, pos, w); 44 + } 27 45 28 - /* Individual selection criteria for different scan areas */ 29 - static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL; 30 - static s32 CR_R2L_T2B = CR_DIAGONAL_BALANCE; 46 + /* 47 + * w width in slots 48 + * pos ptr to position 49 + * map ptr to bitmap 50 + * num_bits number of bits in bitmap 51 + */ 52 + static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map, 53 + size_t num_bits) 54 + { 55 + unsigned long search_count = 0; 56 + unsigned long bit; 57 + bool area_found = false; 31 58 32 - /********************************************* 33 - * TCM API - Sita Implementation 34 - *********************************************/ 35 - static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align, 36 - struct tcm_area *area); 37 - static s32 sita_reserve_1d(struct tcm *tcm, u32 slots, struct tcm_area *area); 38 - static s32 sita_free(struct tcm *tcm, struct tcm_area *area); 39 - static void sita_deinit(struct tcm *tcm); 59 + *pos = num_bits - w; 40 60 41 - /********************************************* 42 - * Main Scanner functions 43 - *********************************************/ 44 - static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align, 45 - struct tcm_area *area); 61 + while (search_count < num_bits) { 62 + bit = find_next_bit(map, num_bits, *pos); 46 63 47 - static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, 48 - struct tcm_area *field, struct tcm_area *area); 64 + if (bit - *pos >= w) { 65 + /* found a long enough free area */ 66 + bitmap_set(map, *pos, w); 67 + area_found = true; 68 + break; 69 + } 49 70 50 - static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, 51 - struct tcm_area *field, struct tcm_area *area); 71 + search_count = num_bits - bit + w; 72 + *pos = bit - w; 73 + } 52 74 53 - static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots, 54 - struct tcm_area *field, struct tcm_area *area); 75 + return (area_found) ? 0 : -ENOMEM; 76 + } 55 77 56 - /********************************************* 57 - * Support Infrastructure Methods 58 - *********************************************/ 59 - static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h); 78 + /* 79 + * w = width in slots 80 + * h = height in slots 81 + * a = align in slots (mask, 2^n-1, 0 is unaligned) 82 + * offset = offset in bytes from 4KiB 83 + * pos = position in bitmap for buffer 84 + * map = bitmap ptr 85 + * num_bits = size of bitmap 86 + * stride = bits in one row of container 87 + */ 88 + static int l2r_t2b(uint16_t w, uint16_t h, uint16_t a, int16_t offset, 89 + unsigned long *pos, unsigned long slot_bytes, 90 + unsigned long *map, size_t num_bits, size_t slot_stride) 91 + { 92 + int i; 93 + unsigned long index; 94 + bool area_free; 95 + unsigned long slots_per_band = PAGE_SIZE / slot_bytes; 96 + unsigned long bit_offset = (offset > 0) ? offset / slot_bytes : 0; 97 + unsigned long curr_bit = bit_offset; 60 98 61 - static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h, 62 - struct tcm_area *field, s32 criteria, 63 - struct score *best); 99 + /* reset alignment to 1 if we are matching a specific offset */ 100 + /* adjust alignment - 1 to get to the format expected in bitmaps */ 101 + a = (offset > 0) ? 0 : a - 1; 64 102 65 - static void get_nearness_factor(struct tcm_area *field, 66 - struct tcm_area *candidate, 67 - struct nearness_factor *nf); 103 + /* FIXME Return error if slots_per_band > stride */ 68 104 69 - static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area, 70 - struct neighbor_stats *stat); 105 + while (curr_bit < num_bits) { 106 + *pos = bitmap_find_next_zero_area(map, num_bits, curr_bit, w, 107 + a); 71 108 72 - static void fill_area(struct tcm *tcm, 73 - struct tcm_area *area, struct tcm_area *parent); 109 + /* skip forward if we are not at right offset */ 110 + if (bit_offset > 0 && (*pos % slots_per_band != bit_offset)) { 111 + curr_bit = ALIGN(*pos, slots_per_band) + bit_offset; 112 + continue; 113 + } 74 114 115 + /* skip forward to next row if we overlap end of row */ 116 + if ((*pos % slot_stride) + w > slot_stride) { 117 + curr_bit = ALIGN(*pos, slot_stride) + bit_offset; 118 + continue; 119 + } 75 120 76 - /*********************************************/ 121 + /* TODO: Handle overlapping 4K boundaries */ 77 122 78 - /********************************************* 79 - * Utility Methods 80 - *********************************************/ 81 - struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr) 123 + /* break out of look if we will go past end of container */ 124 + if ((*pos + slot_stride * h) > num_bits) 125 + break; 126 + 127 + /* generate mask that represents out matching pattern */ 128 + bitmap_clear(mask, 0, slot_stride); 129 + bitmap_set(mask, (*pos % BITS_PER_LONG), w); 130 + 131 + /* assume the area is free until we find an overlap */ 132 + area_free = true; 133 + 134 + /* check subsequent rows to see if complete area is free */ 135 + for (i = 1; i < h; i++) { 136 + index = *pos / BITS_PER_LONG + i * 8; 137 + if (bitmap_intersects(&map[index], mask, 138 + (*pos % BITS_PER_LONG) + w)) { 139 + area_free = false; 140 + break; 141 + } 142 + } 143 + 144 + if (area_free) 145 + break; 146 + 147 + /* go forward past this match */ 148 + if (bit_offset > 0) 149 + curr_bit = ALIGN(*pos, slots_per_band) + bit_offset; 150 + else 151 + curr_bit = *pos + a + 1; 152 + } 153 + 154 + if (area_free) { 155 + /* set area as in-use. iterate over rows */ 156 + for (i = 0, index = *pos; i < h; i++, index += slot_stride) 157 + bitmap_set(map, index, w); 158 + } 159 + 160 + return (area_free) ? 0 : -ENOMEM; 161 + } 162 + 163 + static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, 164 + struct tcm_area *area) 165 + { 166 + unsigned long pos; 167 + int ret; 168 + 169 + spin_lock(&(tcm->lock)); 170 + ret = r2l_b2t_1d(num_slots, &pos, tcm->bitmap, tcm->map_size); 171 + if (!ret) { 172 + area->p0.x = pos % tcm->width; 173 + area->p0.y = pos / tcm->width; 174 + area->p1.x = (pos + num_slots - 1) % tcm->width; 175 + area->p1.y = (pos + num_slots - 1) / tcm->width; 176 + } 177 + spin_unlock(&(tcm->lock)); 178 + 179 + return ret; 180 + } 181 + 182 + static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align, 183 + int16_t offset, uint16_t slot_bytes, 184 + struct tcm_area *area) 185 + { 186 + unsigned long pos; 187 + int ret; 188 + 189 + spin_lock(&(tcm->lock)); 190 + ret = l2r_t2b(w, h, align, offset, &pos, slot_bytes, tcm->bitmap, 191 + tcm->map_size, tcm->width); 192 + 193 + if (!ret) { 194 + area->p0.x = pos % tcm->width; 195 + area->p0.y = pos / tcm->width; 196 + area->p1.x = area->p0.x + w - 1; 197 + area->p1.y = area->p0.y + h - 1; 198 + } 199 + spin_unlock(&(tcm->lock)); 200 + 201 + return ret; 202 + } 203 + 204 + static void sita_deinit(struct tcm *tcm) 205 + { 206 + kfree(tcm); 207 + } 208 + 209 + static s32 sita_free(struct tcm *tcm, struct tcm_area *area) 210 + { 211 + unsigned long pos; 212 + uint16_t w, h; 213 + 214 + pos = area->p0.x + area->p0.y * tcm->width; 215 + if (area->is2d) { 216 + w = area->p1.x - area->p0.x + 1; 217 + h = area->p1.y - area->p0.y + 1; 218 + } else { 219 + w = area->p1.x + area->p1.y * tcm->width - pos + 1; 220 + h = 1; 221 + } 222 + 223 + spin_lock(&(tcm->lock)); 224 + free_slots(pos, w, h, tcm->bitmap, tcm->width); 225 + spin_unlock(&(tcm->lock)); 226 + return 0; 227 + } 228 + 229 + struct tcm *sita_init(u16 width, u16 height) 82 230 { 83 231 struct tcm *tcm; 84 - struct sita_pvt *pvt; 85 - struct tcm_area area = {0}; 86 - s32 i; 232 + size_t map_size = BITS_TO_LONGS(width*height) * sizeof(unsigned long); 87 233 88 234 if (width == 0 || height == 0) 89 235 return NULL; 90 236 91 - tcm = kzalloc(sizeof(*tcm), GFP_KERNEL); 92 - pvt = kzalloc(sizeof(*pvt), GFP_KERNEL); 93 - if (!tcm || !pvt) 237 + tcm = kzalloc(sizeof(*tcm) + map_size, GFP_KERNEL); 238 + if (!tcm) 94 239 goto error; 95 240 96 241 /* Updating the pointers to SiTA implementation APIs */ ··· 246 99 tcm->reserve_1d = sita_reserve_1d; 247 100 tcm->free = sita_free; 248 101 tcm->deinit = sita_deinit; 249 - tcm->pvt = (void *)pvt; 250 102 251 - spin_lock_init(&(pvt->lock)); 103 + spin_lock_init(&tcm->lock); 104 + tcm->bitmap = (unsigned long *)(tcm + 1); 105 + bitmap_clear(tcm->bitmap, 0, width*height); 252 106 253 - /* Creating tam map */ 254 - pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL); 255 - if (!pvt->map) 256 - goto error; 107 + tcm->map_size = width*height; 257 108 258 - for (i = 0; i < tcm->width; i++) { 259 - pvt->map[i] = 260 - kmalloc(sizeof(**pvt->map) * tcm->height, 261 - GFP_KERNEL); 262 - if (pvt->map[i] == NULL) { 263 - while (i--) 264 - kfree(pvt->map[i]); 265 - kfree(pvt->map); 266 - goto error; 267 - } 268 - } 269 - 270 - if (attr && attr->x <= tcm->width && attr->y <= tcm->height) { 271 - pvt->div_pt.x = attr->x; 272 - pvt->div_pt.y = attr->y; 273 - 274 - } else { 275 - /* Defaulting to 3:1 ratio on width for 2D area split */ 276 - /* Defaulting to 3:1 ratio on height for 2D and 1D split */ 277 - pvt->div_pt.x = (tcm->width * 3) / 4; 278 - pvt->div_pt.y = (tcm->height * 3) / 4; 279 - } 280 - 281 - spin_lock(&(pvt->lock)); 282 - assign(&area, 0, 0, width - 1, height - 1); 283 - fill_area(tcm, &area, NULL); 284 - spin_unlock(&(pvt->lock)); 285 109 return tcm; 286 110 287 111 error: 288 112 kfree(tcm); 289 - kfree(pvt); 290 113 return NULL; 291 - } 292 - 293 - static void sita_deinit(struct tcm *tcm) 294 - { 295 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 296 - struct tcm_area area = {0}; 297 - s32 i; 298 - 299 - area.p1.x = tcm->width - 1; 300 - area.p1.y = tcm->height - 1; 301 - 302 - spin_lock(&(pvt->lock)); 303 - fill_area(tcm, &area, NULL); 304 - spin_unlock(&(pvt->lock)); 305 - 306 - for (i = 0; i < tcm->height; i++) 307 - kfree(pvt->map[i]); 308 - kfree(pvt->map); 309 - kfree(pvt); 310 - } 311 - 312 - /** 313 - * Reserve a 1D area in the container 314 - * 315 - * @param num_slots size of 1D area 316 - * @param area pointer to the area that will be populated with the 317 - * reserved area 318 - * 319 - * @return 0 on success, non-0 error value on failure. 320 - */ 321 - static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, 322 - struct tcm_area *area) 323 - { 324 - s32 ret; 325 - struct tcm_area field = {0}; 326 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 327 - 328 - spin_lock(&(pvt->lock)); 329 - 330 - /* Scanning entire container */ 331 - assign(&field, tcm->width - 1, tcm->height - 1, 0, 0); 332 - 333 - ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area); 334 - if (!ret) 335 - /* update map */ 336 - fill_area(tcm, area, area); 337 - 338 - spin_unlock(&(pvt->lock)); 339 - return ret; 340 - } 341 - 342 - /** 343 - * Reserve a 2D area in the container 344 - * 345 - * @param w width 346 - * @param h height 347 - * @param area pointer to the area that will be populated with the reserved 348 - * area 349 - * 350 - * @return 0 on success, non-0 error value on failure. 351 - */ 352 - static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align, 353 - struct tcm_area *area) 354 - { 355 - s32 ret; 356 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 357 - 358 - /* not supporting more than 64 as alignment */ 359 - if (align > 64) 360 - return -EINVAL; 361 - 362 - /* we prefer 1, 32 and 64 as alignment */ 363 - align = align <= 1 ? 1 : align <= 32 ? 32 : 64; 364 - 365 - spin_lock(&(pvt->lock)); 366 - ret = scan_areas_and_find_fit(tcm, w, h, align, area); 367 - if (!ret) 368 - /* update map */ 369 - fill_area(tcm, area, area); 370 - 371 - spin_unlock(&(pvt->lock)); 372 - return ret; 373 - } 374 - 375 - /** 376 - * Unreserve a previously allocated 2D or 1D area 377 - * @param area area to be freed 378 - * @return 0 - success 379 - */ 380 - static s32 sita_free(struct tcm *tcm, struct tcm_area *area) 381 - { 382 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 383 - 384 - spin_lock(&(pvt->lock)); 385 - 386 - /* check that this is in fact an existing area */ 387 - WARN_ON(pvt->map[area->p0.x][area->p0.y] != area || 388 - pvt->map[area->p1.x][area->p1.y] != area); 389 - 390 - /* Clear the contents of the associated tiles in the map */ 391 - fill_area(tcm, area, NULL); 392 - 393 - spin_unlock(&(pvt->lock)); 394 - 395 - return 0; 396 - } 397 - 398 - /** 399 - * Note: In general the cordinates in the scan field area relevant to the can 400 - * sweep directions. The scan origin (e.g. top-left corner) will always be 401 - * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x 402 - * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y 403 - * <= p0.y 404 - */ 405 - 406 - /** 407 - * Raster scan horizontally right to left from top to bottom to find a place for 408 - * a 2D area of given size inside a scan field. 409 - * 410 - * @param w width of desired area 411 - * @param h height of desired area 412 - * @param align desired area alignment 413 - * @param area pointer to the area that will be set to the best position 414 - * @param field area to scan (inclusive) 415 - * 416 - * @return 0 on success, non-0 error value on failure. 417 - */ 418 - static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, 419 - struct tcm_area *field, struct tcm_area *area) 420 - { 421 - s32 x, y; 422 - s16 start_x, end_x, start_y, end_y, found_x = -1; 423 - struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map; 424 - struct score best = {{0}, {0}, {0}, 0}; 425 - 426 - start_x = field->p0.x; 427 - end_x = field->p1.x; 428 - start_y = field->p0.y; 429 - end_y = field->p1.y; 430 - 431 - /* check scan area co-ordinates */ 432 - if (field->p0.x < field->p1.x || 433 - field->p1.y < field->p0.y) 434 - return -EINVAL; 435 - 436 - /* check if allocation would fit in scan area */ 437 - if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y)) 438 - return -ENOSPC; 439 - 440 - /* adjust start_x and end_y, as allocation would not fit beyond */ 441 - start_x = ALIGN_DOWN(start_x - w + 1, align); /* - 1 to be inclusive */ 442 - end_y = end_y - h + 1; 443 - 444 - /* check if allocation would still fit in scan area */ 445 - if (start_x < end_x) 446 - return -ENOSPC; 447 - 448 - /* scan field top-to-bottom, right-to-left */ 449 - for (y = start_y; y <= end_y; y++) { 450 - for (x = start_x; x >= end_x; x -= align) { 451 - if (is_area_free(map, x, y, w, h)) { 452 - found_x = x; 453 - 454 - /* update best candidate */ 455 - if (update_candidate(tcm, x, y, w, h, field, 456 - CR_R2L_T2B, &best)) 457 - goto done; 458 - 459 - /* change upper x bound */ 460 - end_x = x + 1; 461 - break; 462 - } else if (map[x][y] && map[x][y]->is2d) { 463 - /* step over 2D areas */ 464 - x = ALIGN(map[x][y]->p0.x - w + 1, align); 465 - } 466 - } 467 - 468 - /* break if you find a free area shouldering the scan field */ 469 - if (found_x == start_x) 470 - break; 471 - } 472 - 473 - if (!best.a.tcm) 474 - return -ENOSPC; 475 - done: 476 - assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y); 477 - return 0; 478 - } 479 - 480 - /** 481 - * Raster scan horizontally left to right from top to bottom to find a place for 482 - * a 2D area of given size inside a scan field. 483 - * 484 - * @param w width of desired area 485 - * @param h height of desired area 486 - * @param align desired area alignment 487 - * @param area pointer to the area that will be set to the best position 488 - * @param field area to scan (inclusive) 489 - * 490 - * @return 0 on success, non-0 error value on failure. 491 - */ 492 - static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align, 493 - struct tcm_area *field, struct tcm_area *area) 494 - { 495 - s32 x, y; 496 - s16 start_x, end_x, start_y, end_y, found_x = -1; 497 - struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map; 498 - struct score best = {{0}, {0}, {0}, 0}; 499 - 500 - start_x = field->p0.x; 501 - end_x = field->p1.x; 502 - start_y = field->p0.y; 503 - end_y = field->p1.y; 504 - 505 - /* check scan area co-ordinates */ 506 - if (field->p1.x < field->p0.x || 507 - field->p1.y < field->p0.y) 508 - return -EINVAL; 509 - 510 - /* check if allocation would fit in scan area */ 511 - if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y)) 512 - return -ENOSPC; 513 - 514 - start_x = ALIGN(start_x, align); 515 - 516 - /* check if allocation would still fit in scan area */ 517 - if (w > LEN(end_x, start_x)) 518 - return -ENOSPC; 519 - 520 - /* adjust end_x and end_y, as allocation would not fit beyond */ 521 - end_x = end_x - w + 1; /* + 1 to be inclusive */ 522 - end_y = end_y - h + 1; 523 - 524 - /* scan field top-to-bottom, left-to-right */ 525 - for (y = start_y; y <= end_y; y++) { 526 - for (x = start_x; x <= end_x; x += align) { 527 - if (is_area_free(map, x, y, w, h)) { 528 - found_x = x; 529 - 530 - /* update best candidate */ 531 - if (update_candidate(tcm, x, y, w, h, field, 532 - CR_L2R_T2B, &best)) 533 - goto done; 534 - /* change upper x bound */ 535 - end_x = x - 1; 536 - 537 - break; 538 - } else if (map[x][y] && map[x][y]->is2d) { 539 - /* step over 2D areas */ 540 - x = ALIGN_DOWN(map[x][y]->p1.x, align); 541 - } 542 - } 543 - 544 - /* break if you find a free area shouldering the scan field */ 545 - if (found_x == start_x) 546 - break; 547 - } 548 - 549 - if (!best.a.tcm) 550 - return -ENOSPC; 551 - done: 552 - assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y); 553 - return 0; 554 - } 555 - 556 - /** 557 - * Raster scan horizontally right to left from bottom to top to find a place 558 - * for a 1D area of given size inside a scan field. 559 - * 560 - * @param num_slots size of desired area 561 - * @param align desired area alignment 562 - * @param area pointer to the area that will be set to the best 563 - * position 564 - * @param field area to scan (inclusive) 565 - * 566 - * @return 0 on success, non-0 error value on failure. 567 - */ 568 - static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots, 569 - struct tcm_area *field, struct tcm_area *area) 570 - { 571 - s32 found = 0; 572 - s16 x, y; 573 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 574 - struct tcm_area *p; 575 - 576 - /* check scan area co-ordinates */ 577 - if (field->p0.y < field->p1.y) 578 - return -EINVAL; 579 - 580 - /** 581 - * Currently we only support full width 1D scan field, which makes sense 582 - * since 1D slot-ordering spans the full container width. 583 - */ 584 - if (tcm->width != field->p0.x - field->p1.x + 1) 585 - return -EINVAL; 586 - 587 - /* check if allocation would fit in scan area */ 588 - if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y)) 589 - return -ENOSPC; 590 - 591 - x = field->p0.x; 592 - y = field->p0.y; 593 - 594 - /* find num_slots consecutive free slots to the left */ 595 - while (found < num_slots) { 596 - if (y < 0) 597 - return -ENOSPC; 598 - 599 - /* remember bottom-right corner */ 600 - if (found == 0) { 601 - area->p1.x = x; 602 - area->p1.y = y; 603 - } 604 - 605 - /* skip busy regions */ 606 - p = pvt->map[x][y]; 607 - if (p) { 608 - /* move to left of 2D areas, top left of 1D */ 609 - x = p->p0.x; 610 - if (!p->is2d) 611 - y = p->p0.y; 612 - 613 - /* start over */ 614 - found = 0; 615 - } else { 616 - /* count consecutive free slots */ 617 - found++; 618 - if (found == num_slots) 619 - break; 620 - } 621 - 622 - /* move to the left */ 623 - if (x == 0) 624 - y--; 625 - x = (x ? : tcm->width) - 1; 626 - 627 - } 628 - 629 - /* set top-left corner */ 630 - area->p0.x = x; 631 - area->p0.y = y; 632 - return 0; 633 - } 634 - 635 - /** 636 - * Find a place for a 2D area of given size inside a scan field based on its 637 - * alignment needs. 638 - * 639 - * @param w width of desired area 640 - * @param h height of desired area 641 - * @param align desired area alignment 642 - * @param area pointer to the area that will be set to the best position 643 - * 644 - * @return 0 on success, non-0 error value on failure. 645 - */ 646 - static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align, 647 - struct tcm_area *area) 648 - { 649 - s32 ret = 0; 650 - struct tcm_area field = {0}; 651 - u16 boundary_x, boundary_y; 652 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 653 - 654 - if (align > 1) { 655 - /* prefer top-left corner */ 656 - boundary_x = pvt->div_pt.x - 1; 657 - boundary_y = pvt->div_pt.y - 1; 658 - 659 - /* expand width and height if needed */ 660 - if (w > pvt->div_pt.x) 661 - boundary_x = tcm->width - 1; 662 - if (h > pvt->div_pt.y) 663 - boundary_y = tcm->height - 1; 664 - 665 - assign(&field, 0, 0, boundary_x, boundary_y); 666 - ret = scan_l2r_t2b(tcm, w, h, align, &field, area); 667 - 668 - /* scan whole container if failed, but do not scan 2x */ 669 - if (ret != 0 && (boundary_x != tcm->width - 1 || 670 - boundary_y != tcm->height - 1)) { 671 - /* scan the entire container if nothing found */ 672 - assign(&field, 0, 0, tcm->width - 1, tcm->height - 1); 673 - ret = scan_l2r_t2b(tcm, w, h, align, &field, area); 674 - } 675 - } else if (align == 1) { 676 - /* prefer top-right corner */ 677 - boundary_x = pvt->div_pt.x; 678 - boundary_y = pvt->div_pt.y - 1; 679 - 680 - /* expand width and height if needed */ 681 - if (w > (tcm->width - pvt->div_pt.x)) 682 - boundary_x = 0; 683 - if (h > pvt->div_pt.y) 684 - boundary_y = tcm->height - 1; 685 - 686 - assign(&field, tcm->width - 1, 0, boundary_x, boundary_y); 687 - ret = scan_r2l_t2b(tcm, w, h, align, &field, area); 688 - 689 - /* scan whole container if failed, but do not scan 2x */ 690 - if (ret != 0 && (boundary_x != 0 || 691 - boundary_y != tcm->height - 1)) { 692 - /* scan the entire container if nothing found */ 693 - assign(&field, tcm->width - 1, 0, 0, tcm->height - 1); 694 - ret = scan_r2l_t2b(tcm, w, h, align, &field, 695 - area); 696 - } 697 - } 698 - 699 - return ret; 700 - } 701 - 702 - /* check if an entire area is free */ 703 - static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h) 704 - { 705 - u16 x = 0, y = 0; 706 - for (y = y0; y < y0 + h; y++) { 707 - for (x = x0; x < x0 + w; x++) { 708 - if (map[x][y]) 709 - return false; 710 - } 711 - } 712 - return true; 713 - } 714 - 715 - /* fills an area with a parent tcm_area */ 716 - static void fill_area(struct tcm *tcm, struct tcm_area *area, 717 - struct tcm_area *parent) 718 - { 719 - s32 x, y; 720 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 721 - struct tcm_area a, a_; 722 - 723 - /* set area's tcm; otherwise, enumerator considers it invalid */ 724 - area->tcm = tcm; 725 - 726 - tcm_for_each_slice(a, *area, a_) { 727 - for (x = a.p0.x; x <= a.p1.x; ++x) 728 - for (y = a.p0.y; y <= a.p1.y; ++y) 729 - pvt->map[x][y] = parent; 730 - 731 - } 732 - } 733 - 734 - /** 735 - * Compares a candidate area to the current best area, and if it is a better 736 - * fit, it updates the best to this one. 737 - * 738 - * @param x0, y0, w, h top, left, width, height of candidate area 739 - * @param field scan field 740 - * @param criteria scan criteria 741 - * @param best best candidate and its scores 742 - * 743 - * @return 1 (true) if the candidate area is known to be the final best, so no 744 - * more searching should be performed 745 - */ 746 - static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h, 747 - struct tcm_area *field, s32 criteria, 748 - struct score *best) 749 - { 750 - struct score me; /* score for area */ 751 - 752 - /* 753 - * NOTE: For horizontal bias we always give the first found, because our 754 - * scan is horizontal-raster-based and the first candidate will always 755 - * have the horizontal bias. 756 - */ 757 - bool first = criteria & CR_BIAS_HORIZONTAL; 758 - 759 - assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1); 760 - 761 - /* calculate score for current candidate */ 762 - if (!first) { 763 - get_neighbor_stats(tcm, &me.a, &me.n); 764 - me.neighs = me.n.edge + me.n.busy; 765 - get_nearness_factor(field, &me.a, &me.f); 766 - } 767 - 768 - /* the 1st candidate is always the best */ 769 - if (!best->a.tcm) 770 - goto better; 771 - 772 - BUG_ON(first); 773 - 774 - /* diagonal balance check */ 775 - if ((criteria & CR_DIAGONAL_BALANCE) && 776 - best->neighs <= me.neighs && 777 - (best->neighs < me.neighs || 778 - /* this implies that neighs and occupied match */ 779 - best->n.busy < me.n.busy || 780 - (best->n.busy == me.n.busy && 781 - /* check the nearness factor */ 782 - best->f.x + best->f.y > me.f.x + me.f.y))) 783 - goto better; 784 - 785 - /* not better, keep going */ 786 - return 0; 787 - 788 - better: 789 - /* save current area as best */ 790 - memcpy(best, &me, sizeof(me)); 791 - best->a.tcm = tcm; 792 - return first; 793 - } 794 - 795 - /** 796 - * Calculate the nearness factor of an area in a search field. The nearness 797 - * factor is smaller if the area is closer to the search origin. 798 - */ 799 - static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area, 800 - struct nearness_factor *nf) 801 - { 802 - /** 803 - * Using signed math as field coordinates may be reversed if 804 - * search direction is right-to-left or bottom-to-top. 805 - */ 806 - nf->x = (s32)(area->p0.x - field->p0.x) * 1000 / 807 - (field->p1.x - field->p0.x); 808 - nf->y = (s32)(area->p0.y - field->p0.y) * 1000 / 809 - (field->p1.y - field->p0.y); 810 - } 811 - 812 - /* get neighbor statistics */ 813 - static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area, 814 - struct neighbor_stats *stat) 815 - { 816 - s16 x = 0, y = 0; 817 - struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt; 818 - 819 - /* Clearing any exisiting values */ 820 - memset(stat, 0, sizeof(*stat)); 821 - 822 - /* process top & bottom edges */ 823 - for (x = area->p0.x; x <= area->p1.x; x++) { 824 - if (area->p0.y == 0) 825 - stat->edge++; 826 - else if (pvt->map[x][area->p0.y - 1]) 827 - stat->busy++; 828 - 829 - if (area->p1.y == tcm->height - 1) 830 - stat->edge++; 831 - else if (pvt->map[x][area->p1.y + 1]) 832 - stat->busy++; 833 - } 834 - 835 - /* process left & right edges */ 836 - for (y = area->p0.y; y <= area->p1.y; ++y) { 837 - if (area->p0.x == 0) 838 - stat->edge++; 839 - else if (pvt->map[area->p0.x - 1][y]) 840 - stat->busy++; 841 - 842 - if (area->p1.x == tcm->width - 1) 843 - stat->edge++; 844 - else if (pvt->map[area->p1.x + 1][y]) 845 - stat->busy++; 846 - } 847 114 }
+15 -11
drivers/gpu/drm/omapdrm/tcm.h
··· 61 61 62 62 unsigned int y_offset; /* offset to use for y coordinates */ 63 63 64 - /* 'pvt' structure shall contain any tcm details (attr) along with 65 - linked list of allocated areas and mutex for mutually exclusive access 66 - to the list. It may also contain copies of width and height to notice 67 - any changes to the publicly available width and height fields. */ 68 - void *pvt; 64 + spinlock_t lock; 65 + unsigned long *bitmap; 66 + size_t map_size; 69 67 70 68 /* function table */ 71 - s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u8 align, 69 + s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align, 70 + int16_t offset, uint16_t slot_bytes, 72 71 struct tcm_area *area); 73 72 s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area); 74 - s32 (*free) (struct tcm *tcm, struct tcm_area *area); 75 - void (*deinit) (struct tcm *tcm); 73 + s32 (*free)(struct tcm *tcm, struct tcm_area *area); 74 + void (*deinit)(struct tcm *tcm); 76 75 }; 77 76 78 77 /*============================================================================= ··· 90 91 * 91 92 */ 92 93 93 - struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr); 94 + struct tcm *sita_init(u16 width, u16 height); 94 95 95 96 96 97 /** ··· 119 120 * all values may be supported by the container manager, 120 121 * but it must support 0 (1), 32 and 64. 121 122 * 0 value is equivalent to 1. 123 + * @param offset Offset requirement, in bytes. This is the offset 124 + * from a 4KiB aligned virtual address. 125 + * @param slot_bytes Width of slot in bytes 122 126 * @param area Pointer to where the reserved area should be stored. 123 127 * 124 128 * @return 0 on success. Non-0 error code on failure. Also, ··· 131 129 * allocation. 132 130 */ 133 131 static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height, 134 - u16 align, struct tcm_area *area) 132 + u16 align, int16_t offset, uint16_t slot_bytes, 133 + struct tcm_area *area) 135 134 { 136 135 /* perform rudimentary error checking */ 137 136 s32 res = tcm == NULL ? -ENODEV : ··· 143 140 144 141 if (!res) { 145 142 area->is2d = true; 146 - res = tcm->reserve_2d(tcm, height, width, align, area); 143 + res = tcm->reserve_2d(tcm, height, width, align, offset, 144 + slot_bytes, area); 147 145 area->tcm = res ? NULL : tcm; 148 146 } 149 147