cregit-Linux how code gets into the kernel

Release 4.11 drivers/gpu/drm/omapdrm/tcm-sita.c

/*
 * tcm-sita.c
 *
 * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
 *
 * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
 *          Lajos Molnar <molnar@ti.com>
 *          Andy Gross <andy.gross@ti.com>
 *
 * Copyright (C) 2012 Texas Instruments, Inc.
 *
 * This package is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/bitmap.h>
#include <linux/slab.h>
#include "tcm.h"


static unsigned long mask[8];
/*
 * pos          position in bitmap
 * w            width in slots
 * h            height in slots
 * map          ptr to bitmap
 * stride               slots in a row
 */

static void free_slots(unsigned long pos, uint16_t w, uint16_t h, unsigned long *map, uint16_t stride) { int i; for (i = 0; i < h; i++, pos += stride) bitmap_clear(map, pos, w); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross53100.00%2100.00%
Total53100.00%2100.00%

/* * w width in slots * pos ptr to position * map ptr to bitmap * num_bits number of bits in bitmap */
static int r2l_b2t_1d(uint16_t w, unsigned long *pos, unsigned long *map, size_t num_bits) { unsigned long search_count = 0; unsigned long bit; bool area_found = false; *pos = num_bits - w; while (search_count < num_bits) { bit = find_next_bit(map, num_bits, *pos); if (bit - *pos >= w) { /* found a long enough free area */ bitmap_set(map, *pos, w); area_found = true; break; } search_count = num_bits - bit + w; *pos = bit - w; } return (area_found) ? 0 : -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross116100.00%2100.00%
Total116100.00%2100.00%

/* * w = width in slots * h = height in slots * a = align in slots (mask, 2^n-1, 0 is unaligned) * offset = offset in bytes from 4KiB * pos = position in bitmap for buffer * map = bitmap ptr * num_bits = size of bitmap * stride = bits in one row of container */
static int l2r_t2b(uint16_t w, uint16_t h, uint16_t a, int16_t offset, unsigned long *pos, unsigned long slot_bytes, unsigned long *map, size_t num_bits, size_t slot_stride) { int i; unsigned long index; bool area_free; unsigned long slots_per_band = PAGE_SIZE / slot_bytes; unsigned long bit_offset = (offset > 0) ? offset / slot_bytes : 0; unsigned long curr_bit = bit_offset; /* reset alignment to 1 if we are matching a specific offset */ /* adjust alignment - 1 to get to the format expected in bitmaps */ a = (offset > 0) ? 0 : a - 1; /* FIXME Return error if slots_per_band > stride */ while (curr_bit < num_bits) { *pos = bitmap_find_next_zero_area(map, num_bits, curr_bit, w, a); /* skip forward if we are not at right offset */ if (bit_offset > 0 && (*pos % slots_per_band != bit_offset)) { curr_bit = ALIGN(*pos, slots_per_band) + bit_offset; continue; } /* skip forward to next row if we overlap end of row */ if ((*pos % slot_stride) + w > slot_stride) { curr_bit = ALIGN(*pos, slot_stride) + bit_offset; continue; } /* TODO: Handle overlapping 4K boundaries */ /* break out of look if we will go past end of container */ if ((*pos + slot_stride * h) > num_bits) break; /* generate mask that represents out matching pattern */ bitmap_clear(mask, 0, slot_stride); bitmap_set(mask, (*pos % BITS_PER_LONG), w); /* assume the area is free until we find an overlap */ area_free = true; /* check subsequent rows to see if complete area is free */ for (i = 1; i < h; i++) { index = *pos / BITS_PER_LONG + i * 8; if (bitmap_intersects(&map[index], mask, (*pos % BITS_PER_LONG) + w)) { area_free = false; break; } } if (area_free) break; /* go forward past this match */ if (bit_offset > 0) curr_bit = ALIGN(*pos, slots_per_band) + bit_offset; else curr_bit = *pos + a + 1; } if (area_free) { /* set area as in-use. iterate over rows */ for (i = 0, index = *pos; i < h; i++, index += slot_stride) bitmap_set(map, index, w); } return (area_free) ? 0 : -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross362100.00%2100.00%
Total362100.00%2100.00%


static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots, struct tcm_area *area) { unsigned long pos; int ret; spin_lock(&(tcm->lock)); ret = r2l_b2t_1d(num_slots, &pos, tcm->bitmap, tcm->map_size); if (!ret) { area->p0.x = pos % tcm->width; area->p0.y = pos / tcm->width; area->p1.x = (pos + num_slots - 1) % tcm->width; area->p1.y = (pos + num_slots - 1) / tcm->width; } spin_unlock(&(tcm->lock)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross134100.00%2100.00%
Total134100.00%2100.00%


static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u16 align, int16_t offset, uint16_t slot_bytes, struct tcm_area *area) { unsigned long pos; int ret; spin_lock(&(tcm->lock)); ret = l2r_t2b(w, h, align, offset, &pos, slot_bytes, tcm->bitmap, tcm->map_size, tcm->width); if (!ret) { area->p0.x = pos % tcm->width; area->p0.y = pos / tcm->width; area->p1.x = area->p0.x + w - 1; area->p1.y = area->p0.y + h - 1; } spin_unlock(&(tcm->lock)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross154100.00%2100.00%
Total154100.00%2100.00%


static void sita_deinit(struct tcm *tcm) { kfree(tcm); }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross16100.00%2100.00%
Total16100.00%2100.00%


static s32 sita_free(struct tcm *tcm, struct tcm_area *area) { unsigned long pos; uint16_t w, h; pos = area->p0.x + area->p0.y * tcm->width; if (area->is2d) { w = area->p1.x - area->p0.x + 1; h = area->p1.y - area->p0.y + 1; } else { w = area->p1.x + area->p1.y * tcm->width - pos + 1; h = 1; } spin_lock(&(tcm->lock)); free_slots(pos, w, h, tcm->bitmap, tcm->width); spin_unlock(&(tcm->lock)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross152100.00%2100.00%
Total152100.00%2100.00%


struct tcm *sita_init(u16 width, u16 height) { struct tcm *tcm; size_t map_size = BITS_TO_LONGS(width*height) * sizeof(unsigned long); if (width == 0 || height == 0) return NULL; tcm = kzalloc(sizeof(*tcm) + map_size, GFP_KERNEL); if (!tcm) goto error; /* Updating the pointers to SiTA implementation APIs */ tcm->height = height; tcm->width = width; tcm->reserve_2d = sita_reserve_2d; tcm->reserve_1d = sita_reserve_1d; tcm->free = sita_free; tcm->deinit = sita_deinit; spin_lock_init(&tcm->lock); tcm->bitmap = (unsigned long *)(tcm + 1); bitmap_clear(tcm->bitmap, 0, width*height); tcm->map_size = width*height; return tcm; error: kfree(tcm); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Andy Gross164100.00%2100.00%
Total164100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Andy Gross1187100.00%2100.00%
Total1187100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.