root/drivers/gpu/drm/omapdrm/tcm-sita.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. free_slots
  2. r2l_b2t_1d
  3. l2r_t2b
  4. sita_reserve_1d
  5. sita_reserve_2d
  6. sita_deinit
  7. sita_free
  8. sita_init

   1 /*
   2  * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
   3  *
   4  * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
   5  *          Lajos Molnar <molnar@ti.com>
   6  *          Andy Gross <andy.gross@ti.com>
   7  *
   8  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
   9  *
  10  * This package is free software; you can redistribute it and/or modify
  11  * it under the terms of the GNU General Public License version 2 as
  12  * published by the Free Software Foundation.
  13  *
  14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  17  *
  18  */
  19 #include <linux/init.h>
  20 #include <linux/module.h>
  21 #include <linux/errno.h>
  22 #include <linux/sched.h>
  23 #include <linux/wait.h>
  24 #include <linux/bitmap.h>
  25 #include <linux/slab.h>
  26 #include "tcm.h"
  27 
  28 static unsigned long mask[8];
  29 /*
  30  * pos          position in bitmap
  31  * w            width in slots
  32  * h            height in slots
  33  * map          ptr to bitmap
  34  * stride               slots in a row
  35  */
  36 static void free_slots(unsigned long pos, u16 w, u16 h,
  37                 unsigned long *map, u16 stride)
  38 {
  39         int i;
  40 
  41         for (i = 0; i < h; i++, pos += stride)
  42                 bitmap_clear(map, pos, w);
  43 }
  44 
  45 /*
  46  * w            width in slots
  47  * pos          ptr to position
  48  * map          ptr to bitmap
  49  * num_bits     number of bits in bitmap
  50  */
  51 static int r2l_b2t_1d(u16 w, unsigned long *pos, unsigned long *map,
  52                 size_t num_bits)
  53 {
  54         unsigned long search_count = 0;
  55         unsigned long bit;
  56         bool area_found = false;
  57 
  58         *pos = num_bits - w;
  59 
  60         while (search_count < num_bits) {
  61                 bit = find_next_bit(map, num_bits, *pos);
  62 
  63                 if (bit - *pos >= w) {
  64                         /* found a long enough free area */
  65                         bitmap_set(map, *pos, w);
  66                         area_found = true;
  67                         break;
  68                 }
  69 
  70                 search_count = num_bits - bit + w;
  71                 *pos = bit - w;
  72         }
  73 
  74         return (area_found) ? 0 : -ENOMEM;
  75 }
  76 
  77 /*
  78  * w = width in slots
  79  * h = height in slots
  80  * a = align in slots   (mask, 2^n-1, 0 is unaligned)
  81  * offset = offset in bytes from 4KiB
  82  * pos = position in bitmap for buffer
  83  * map = bitmap ptr
  84  * num_bits = size of bitmap
  85  * stride = bits in one row of container
  86  */
  87 static int l2r_t2b(u16 w, u16 h, u16 a, s16 offset,
  88                 unsigned long *pos, unsigned long slot_bytes,
  89                 unsigned long *map, size_t num_bits, size_t slot_stride)
  90 {
  91         int i;
  92         unsigned long index;
  93         bool area_free = false;
  94         unsigned long slots_per_band = PAGE_SIZE / slot_bytes;
  95         unsigned long bit_offset = (offset > 0) ? offset / slot_bytes : 0;
  96         unsigned long curr_bit = bit_offset;
  97 
  98         /* reset alignment to 1 if we are matching a specific offset */
  99         /* adjust alignment - 1 to get to the format expected in bitmaps */
 100         a = (offset > 0) ? 0 : a - 1;
 101 
 102         /* FIXME Return error if slots_per_band > stride */
 103 
 104         while (curr_bit < num_bits) {
 105                 *pos = bitmap_find_next_zero_area(map, num_bits, curr_bit, w,
 106                                 a);
 107 
 108                 /* skip forward if we are not at right offset */
 109                 if (bit_offset > 0 && (*pos % slots_per_band != bit_offset)) {
 110                         curr_bit = ALIGN(*pos, slots_per_band) + bit_offset;
 111                         continue;
 112                 }
 113 
 114                 /* skip forward to next row if we overlap end of row */
 115                 if ((*pos % slot_stride) + w > slot_stride) {
 116                         curr_bit = ALIGN(*pos, slot_stride) + bit_offset;
 117                         continue;
 118                 }
 119 
 120                 /* TODO: Handle overlapping 4K boundaries */
 121 
 122                 /* break out of look if we will go past end of container */
 123                 if ((*pos + slot_stride * h) > num_bits)
 124                         break;
 125 
 126                 /* generate mask that represents out matching pattern */
 127                 bitmap_clear(mask, 0, slot_stride);
 128                 bitmap_set(mask, (*pos % BITS_PER_LONG), w);
 129 
 130                 /* assume the area is free until we find an overlap */
 131                 area_free = true;
 132 
 133                 /* check subsequent rows to see if complete area is free */
 134                 for (i = 1; i < h; i++) {
 135                         index = *pos / BITS_PER_LONG + i * 8;
 136                         if (bitmap_intersects(&map[index], mask,
 137                                 (*pos % BITS_PER_LONG) + w)) {
 138                                 area_free = false;
 139                                 break;
 140                         }
 141                 }
 142 
 143                 if (area_free)
 144                         break;
 145 
 146                 /* go forward past this match */
 147                 if (bit_offset > 0)
 148                         curr_bit = ALIGN(*pos, slots_per_band) + bit_offset;
 149                 else
 150                         curr_bit = *pos + a + 1;
 151         }
 152 
 153         if (area_free) {
 154                 /* set area as in-use. iterate over rows */
 155                 for (i = 0, index = *pos; i < h; i++, index += slot_stride)
 156                         bitmap_set(map, index, w);
 157         }
 158 
 159         return (area_free) ? 0 : -ENOMEM;
 160 }
 161 
 162 static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
 163                            struct tcm_area *area)
 164 {
 165         unsigned long pos;
 166         int ret;
 167 
 168         spin_lock(&(tcm->lock));
 169         ret = r2l_b2t_1d(num_slots, &pos, tcm->bitmap, tcm->map_size);
 170         if (!ret) {
 171                 area->p0.x = pos % tcm->width;
 172                 area->p0.y = pos / tcm->width;
 173                 area->p1.x = (pos + num_slots - 1) % tcm->width;
 174                 area->p1.y = (pos + num_slots - 1) / tcm->width;
 175         }
 176         spin_unlock(&(tcm->lock));
 177 
 178         return ret;
 179 }
 180 
 181 static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align,
 182                                 s16 offset, u16 slot_bytes,
 183                                 struct tcm_area *area)
 184 {
 185         unsigned long pos;
 186         int ret;
 187 
 188         spin_lock(&(tcm->lock));
 189         ret = l2r_t2b(w, h, align, offset, &pos, slot_bytes, tcm->bitmap,
 190                         tcm->map_size, tcm->width);
 191 
 192         if (!ret) {
 193                 area->p0.x = pos % tcm->width;
 194                 area->p0.y = pos / tcm->width;
 195                 area->p1.x = area->p0.x + w - 1;
 196                 area->p1.y = area->p0.y + h - 1;
 197         }
 198         spin_unlock(&(tcm->lock));
 199 
 200         return ret;
 201 }
 202 
 203 static void sita_deinit(struct tcm *tcm)
 204 {
 205         kfree(tcm);
 206 }
 207 
 208 static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
 209 {
 210         unsigned long pos;
 211         u16 w, h;
 212 
 213         pos = area->p0.x + area->p0.y * tcm->width;
 214         if (area->is2d) {
 215                 w = area->p1.x - area->p0.x + 1;
 216                 h = area->p1.y - area->p0.y + 1;
 217         } else {
 218                 w = area->p1.x + area->p1.y * tcm->width - pos + 1;
 219                 h = 1;
 220         }
 221 
 222         spin_lock(&(tcm->lock));
 223         free_slots(pos, w, h, tcm->bitmap, tcm->width);
 224         spin_unlock(&(tcm->lock));
 225         return 0;
 226 }
 227 
 228 struct tcm *sita_init(u16 width, u16 height)
 229 {
 230         struct tcm *tcm;
 231         size_t map_size = BITS_TO_LONGS(width*height) * sizeof(unsigned long);
 232 
 233         if (width == 0 || height == 0)
 234                 return NULL;
 235 
 236         tcm = kzalloc(sizeof(*tcm) + map_size, GFP_KERNEL);
 237         if (!tcm)
 238                 goto error;
 239 
 240         /* Updating the pointers to SiTA implementation APIs */
 241         tcm->height = height;
 242         tcm->width = width;
 243         tcm->reserve_2d = sita_reserve_2d;
 244         tcm->reserve_1d = sita_reserve_1d;
 245         tcm->free = sita_free;
 246         tcm->deinit = sita_deinit;
 247 
 248         spin_lock_init(&tcm->lock);
 249         tcm->bitmap = (unsigned long *)(tcm + 1);
 250         bitmap_clear(tcm->bitmap, 0, width*height);
 251 
 252         tcm->map_size = width*height;
 253 
 254         return tcm;
 255 
 256 error:
 257         kfree(tcm);
 258         return NULL;
 259 }

/* [<][>][^][v][top][bottom][index][help] */