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>
This commit is contained in:
parent
73d77107b8
commit
0d6fa53fd8
@ -363,6 +363,7 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
|
|||||||
u32 min_align = 128;
|
u32 min_align = 128;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
size_t slot_bytes;
|
||||||
|
|
||||||
BUG_ON(!validfmt(fmt));
|
BUG_ON(!validfmt(fmt));
|
||||||
|
|
||||||
@ -371,13 +372,15 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
|
|||||||
h = DIV_ROUND_UP(h, geom[fmt].slot_h);
|
h = DIV_ROUND_UP(h, geom[fmt].slot_h);
|
||||||
|
|
||||||
/* convert alignment to slots */
|
/* convert alignment to slots */
|
||||||
min_align = max(min_align, (geom[fmt].slot_w * geom[fmt].cpp));
|
slot_bytes = geom[fmt].slot_w * geom[fmt].cpp;
|
||||||
align = ALIGN(align, min_align);
|
min_align = max(min_align, slot_bytes);
|
||||||
align /= geom[fmt].slot_w * geom[fmt].cpp;
|
align = (align > min_align) ? ALIGN(align, min_align) : min_align;
|
||||||
|
align /= slot_bytes;
|
||||||
|
|
||||||
block->fmt = fmt;
|
block->fmt = fmt;
|
||||||
|
|
||||||
ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area);
|
ret = tcm_reserve_2d(containers[fmt], w, h, align, -1, slot_bytes,
|
||||||
|
&block->area);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
kfree(block);
|
kfree(block);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
@ -739,8 +742,7 @@ static int omap_dmm_probe(struct platform_device *dev)
|
|||||||
programming during reill operations */
|
programming during reill operations */
|
||||||
for (i = 0; i < omap_dmm->num_lut; i++) {
|
for (i = 0; i < omap_dmm->num_lut; i++) {
|
||||||
omap_dmm->tcm[i] = sita_init(omap_dmm->container_width,
|
omap_dmm->tcm[i] = sita_init(omap_dmm->container_width,
|
||||||
omap_dmm->container_height,
|
omap_dmm->container_height);
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (!omap_dmm->tcm[i]) {
|
if (!omap_dmm->tcm[i]) {
|
||||||
dev_err(&dev->dev, "failed to allocate container\n");
|
dev_err(&dev->dev, "failed to allocate container\n");
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
*
|
*
|
||||||
* Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
|
* Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
|
||||||
* Lajos Molnar <molnar@ti.com>
|
* Lajos Molnar <molnar@ti.com>
|
||||||
|
* Andy Gross <andy.gross@ti.com>
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2010 Texas Instruments, Inc.
|
* Copyright (C) 2012 Texas Instruments, Inc.
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@ -17,79 +18,225 @@
|
|||||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
* 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 <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include "tcm.h"
|
||||||
|
|
||||||
#include "tcm-sita.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;
|
||||||
|
|
||||||
#define ALIGN_DOWN(value, align) ((value) & ~((align) - 1))
|
for (i = 0; i < h; i++, pos += stride)
|
||||||
|
bitmap_clear(map, pos, w);
|
||||||
|
}
|
||||||
|
|
||||||
/* Individual selection criteria for different scan areas */
|
/*
|
||||||
static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL;
|
* w width in slots
|
||||||
static s32 CR_R2L_T2B = CR_DIAGONAL_BALANCE;
|
* 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;
|
||||||
* TCM API - Sita Implementation
|
|
||||||
*********************************************/
|
|
||||||
static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
|
|
||||||
struct tcm_area *area);
|
|
||||||
static s32 sita_reserve_1d(struct tcm *tcm, u32 slots, struct tcm_area *area);
|
|
||||||
static s32 sita_free(struct tcm *tcm, struct tcm_area *area);
|
|
||||||
static void sita_deinit(struct tcm *tcm);
|
|
||||||
|
|
||||||
/*********************************************
|
while (search_count < num_bits) {
|
||||||
* Main Scanner functions
|
bit = find_next_bit(map, num_bits, *pos);
|
||||||
*********************************************/
|
|
||||||
static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
|
|
||||||
struct tcm_area *area);
|
|
||||||
|
|
||||||
static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
|
if (bit - *pos >= w) {
|
||||||
struct tcm_area *field, struct tcm_area *area);
|
/* found a long enough free area */
|
||||||
|
bitmap_set(map, *pos, w);
|
||||||
|
area_found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
|
search_count = num_bits - bit + w;
|
||||||
struct tcm_area *field, struct tcm_area *area);
|
*pos = bit - w;
|
||||||
|
}
|
||||||
|
|
||||||
static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
|
return (area_found) ? 0 : -ENOMEM;
|
||||||
struct tcm_area *field, struct tcm_area *area);
|
}
|
||||||
|
|
||||||
/*********************************************
|
/*
|
||||||
* Support Infrastructure Methods
|
* w = width in slots
|
||||||
*********************************************/
|
* h = height in slots
|
||||||
static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
|
* 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;
|
||||||
|
|
||||||
static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
|
/* reset alignment to 1 if we are matching a specific offset */
|
||||||
struct tcm_area *field, s32 criteria,
|
/* adjust alignment - 1 to get to the format expected in bitmaps */
|
||||||
struct score *best);
|
a = (offset > 0) ? 0 : a - 1;
|
||||||
|
|
||||||
static void get_nearness_factor(struct tcm_area *field,
|
/* FIXME Return error if slots_per_band > stride */
|
||||||
struct tcm_area *candidate,
|
|
||||||
struct nearness_factor *nf);
|
|
||||||
|
|
||||||
static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
|
while (curr_bit < num_bits) {
|
||||||
struct neighbor_stats *stat);
|
*pos = bitmap_find_next_zero_area(map, num_bits, curr_bit, w,
|
||||||
|
a);
|
||||||
|
|
||||||
static void fill_area(struct tcm *tcm,
|
/* skip forward if we are not at right offset */
|
||||||
struct tcm_area *area, struct tcm_area *parent);
|
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 */
|
||||||
* Utility Methods
|
if ((*pos + slot_stride * h) > num_bits)
|
||||||
*********************************************/
|
break;
|
||||||
struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sita_deinit(struct tcm *tcm)
|
||||||
|
{
|
||||||
|
kfree(tcm);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tcm *sita_init(u16 width, u16 height)
|
||||||
{
|
{
|
||||||
struct tcm *tcm;
|
struct tcm *tcm;
|
||||||
struct sita_pvt *pvt;
|
size_t map_size = BITS_TO_LONGS(width*height) * sizeof(unsigned long);
|
||||||
struct tcm_area area = {0};
|
|
||||||
s32 i;
|
|
||||||
|
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
tcm = kzalloc(sizeof(*tcm), GFP_KERNEL);
|
tcm = kzalloc(sizeof(*tcm) + map_size, GFP_KERNEL);
|
||||||
pvt = kzalloc(sizeof(*pvt), GFP_KERNEL);
|
if (!tcm)
|
||||||
if (!tcm || !pvt)
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Updating the pointers to SiTA implementation APIs */
|
/* Updating the pointers to SiTA implementation APIs */
|
||||||
@ -99,602 +246,16 @@ struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
|
|||||||
tcm->reserve_1d = sita_reserve_1d;
|
tcm->reserve_1d = sita_reserve_1d;
|
||||||
tcm->free = sita_free;
|
tcm->free = sita_free;
|
||||||
tcm->deinit = sita_deinit;
|
tcm->deinit = sita_deinit;
|
||||||
tcm->pvt = (void *)pvt;
|
|
||||||
|
|
||||||
spin_lock_init(&(pvt->lock));
|
spin_lock_init(&tcm->lock);
|
||||||
|
tcm->bitmap = (unsigned long *)(tcm + 1);
|
||||||
|
bitmap_clear(tcm->bitmap, 0, width*height);
|
||||||
|
|
||||||
/* Creating tam map */
|
tcm->map_size = width*height;
|
||||||
pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
|
|
||||||
if (!pvt->map)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
for (i = 0; i < tcm->width; i++) {
|
|
||||||
pvt->map[i] =
|
|
||||||
kmalloc(sizeof(**pvt->map) * tcm->height,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (pvt->map[i] == NULL) {
|
|
||||||
while (i--)
|
|
||||||
kfree(pvt->map[i]);
|
|
||||||
kfree(pvt->map);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attr && attr->x <= tcm->width && attr->y <= tcm->height) {
|
|
||||||
pvt->div_pt.x = attr->x;
|
|
||||||
pvt->div_pt.y = attr->y;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Defaulting to 3:1 ratio on width for 2D area split */
|
|
||||||
/* Defaulting to 3:1 ratio on height for 2D and 1D split */
|
|
||||||
pvt->div_pt.x = (tcm->width * 3) / 4;
|
|
||||||
pvt->div_pt.y = (tcm->height * 3) / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&(pvt->lock));
|
|
||||||
assign(&area, 0, 0, width - 1, height - 1);
|
|
||||||
fill_area(tcm, &area, NULL);
|
|
||||||
spin_unlock(&(pvt->lock));
|
|
||||||
return tcm;
|
return tcm;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
kfree(tcm);
|
kfree(tcm);
|
||||||
kfree(pvt);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sita_deinit(struct tcm *tcm)
|
|
||||||
{
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
struct tcm_area area = {0};
|
|
||||||
s32 i;
|
|
||||||
|
|
||||||
area.p1.x = tcm->width - 1;
|
|
||||||
area.p1.y = tcm->height - 1;
|
|
||||||
|
|
||||||
spin_lock(&(pvt->lock));
|
|
||||||
fill_area(tcm, &area, NULL);
|
|
||||||
spin_unlock(&(pvt->lock));
|
|
||||||
|
|
||||||
for (i = 0; i < tcm->height; i++)
|
|
||||||
kfree(pvt->map[i]);
|
|
||||||
kfree(pvt->map);
|
|
||||||
kfree(pvt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reserve a 1D area in the container
|
|
||||||
*
|
|
||||||
* @param num_slots size of 1D area
|
|
||||||
* @param area pointer to the area that will be populated with the
|
|
||||||
* reserved area
|
|
||||||
*
|
|
||||||
* @return 0 on success, non-0 error value on failure.
|
|
||||||
*/
|
|
||||||
static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
|
|
||||||
struct tcm_area *area)
|
|
||||||
{
|
|
||||||
s32 ret;
|
|
||||||
struct tcm_area field = {0};
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
|
|
||||||
spin_lock(&(pvt->lock));
|
|
||||||
|
|
||||||
/* Scanning entire container */
|
|
||||||
assign(&field, tcm->width - 1, tcm->height - 1, 0, 0);
|
|
||||||
|
|
||||||
ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area);
|
|
||||||
if (!ret)
|
|
||||||
/* update map */
|
|
||||||
fill_area(tcm, area, area);
|
|
||||||
|
|
||||||
spin_unlock(&(pvt->lock));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reserve a 2D area in the container
|
|
||||||
*
|
|
||||||
* @param w width
|
|
||||||
* @param h height
|
|
||||||
* @param area pointer to the area that will be populated with the reserved
|
|
||||||
* area
|
|
||||||
*
|
|
||||||
* @return 0 on success, non-0 error value on failure.
|
|
||||||
*/
|
|
||||||
static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
|
|
||||||
struct tcm_area *area)
|
|
||||||
{
|
|
||||||
s32 ret;
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
|
|
||||||
/* not supporting more than 64 as alignment */
|
|
||||||
if (align > 64)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* we prefer 1, 32 and 64 as alignment */
|
|
||||||
align = align <= 1 ? 1 : align <= 32 ? 32 : 64;
|
|
||||||
|
|
||||||
spin_lock(&(pvt->lock));
|
|
||||||
ret = scan_areas_and_find_fit(tcm, w, h, align, area);
|
|
||||||
if (!ret)
|
|
||||||
/* update map */
|
|
||||||
fill_area(tcm, area, area);
|
|
||||||
|
|
||||||
spin_unlock(&(pvt->lock));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unreserve a previously allocated 2D or 1D area
|
|
||||||
* @param area area to be freed
|
|
||||||
* @return 0 - success
|
|
||||||
*/
|
|
||||||
static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
|
|
||||||
{
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
|
|
||||||
spin_lock(&(pvt->lock));
|
|
||||||
|
|
||||||
/* check that this is in fact an existing area */
|
|
||||||
WARN_ON(pvt->map[area->p0.x][area->p0.y] != area ||
|
|
||||||
pvt->map[area->p1.x][area->p1.y] != area);
|
|
||||||
|
|
||||||
/* Clear the contents of the associated tiles in the map */
|
|
||||||
fill_area(tcm, area, NULL);
|
|
||||||
|
|
||||||
spin_unlock(&(pvt->lock));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: In general the cordinates in the scan field area relevant to the can
|
|
||||||
* sweep directions. The scan origin (e.g. top-left corner) will always be
|
|
||||||
* the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x
|
|
||||||
* and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y
|
|
||||||
* <= p0.y
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raster scan horizontally right to left from top to bottom to find a place for
|
|
||||||
* a 2D area of given size inside a scan field.
|
|
||||||
*
|
|
||||||
* @param w width of desired area
|
|
||||||
* @param h height of desired area
|
|
||||||
* @param align desired area alignment
|
|
||||||
* @param area pointer to the area that will be set to the best position
|
|
||||||
* @param field area to scan (inclusive)
|
|
||||||
*
|
|
||||||
* @return 0 on success, non-0 error value on failure.
|
|
||||||
*/
|
|
||||||
static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
|
|
||||||
struct tcm_area *field, struct tcm_area *area)
|
|
||||||
{
|
|
||||||
s32 x, y;
|
|
||||||
s16 start_x, end_x, start_y, end_y, found_x = -1;
|
|
||||||
struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
|
|
||||||
struct score best = {{0}, {0}, {0}, 0};
|
|
||||||
|
|
||||||
start_x = field->p0.x;
|
|
||||||
end_x = field->p1.x;
|
|
||||||
start_y = field->p0.y;
|
|
||||||
end_y = field->p1.y;
|
|
||||||
|
|
||||||
/* check scan area co-ordinates */
|
|
||||||
if (field->p0.x < field->p1.x ||
|
|
||||||
field->p1.y < field->p0.y)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* check if allocation would fit in scan area */
|
|
||||||
if (w > LEN(start_x, end_x) || h > LEN(end_y, start_y))
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
/* adjust start_x and end_y, as allocation would not fit beyond */
|
|
||||||
start_x = ALIGN_DOWN(start_x - w + 1, align); /* - 1 to be inclusive */
|
|
||||||
end_y = end_y - h + 1;
|
|
||||||
|
|
||||||
/* check if allocation would still fit in scan area */
|
|
||||||
if (start_x < end_x)
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
/* scan field top-to-bottom, right-to-left */
|
|
||||||
for (y = start_y; y <= end_y; y++) {
|
|
||||||
for (x = start_x; x >= end_x; x -= align) {
|
|
||||||
if (is_area_free(map, x, y, w, h)) {
|
|
||||||
found_x = x;
|
|
||||||
|
|
||||||
/* update best candidate */
|
|
||||||
if (update_candidate(tcm, x, y, w, h, field,
|
|
||||||
CR_R2L_T2B, &best))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* change upper x bound */
|
|
||||||
end_x = x + 1;
|
|
||||||
break;
|
|
||||||
} else if (map[x][y] && map[x][y]->is2d) {
|
|
||||||
/* step over 2D areas */
|
|
||||||
x = ALIGN(map[x][y]->p0.x - w + 1, align);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* break if you find a free area shouldering the scan field */
|
|
||||||
if (found_x == start_x)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!best.a.tcm)
|
|
||||||
return -ENOSPC;
|
|
||||||
done:
|
|
||||||
assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raster scan horizontally left to right from top to bottom to find a place for
|
|
||||||
* a 2D area of given size inside a scan field.
|
|
||||||
*
|
|
||||||
* @param w width of desired area
|
|
||||||
* @param h height of desired area
|
|
||||||
* @param align desired area alignment
|
|
||||||
* @param area pointer to the area that will be set to the best position
|
|
||||||
* @param field area to scan (inclusive)
|
|
||||||
*
|
|
||||||
* @return 0 on success, non-0 error value on failure.
|
|
||||||
*/
|
|
||||||
static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
|
|
||||||
struct tcm_area *field, struct tcm_area *area)
|
|
||||||
{
|
|
||||||
s32 x, y;
|
|
||||||
s16 start_x, end_x, start_y, end_y, found_x = -1;
|
|
||||||
struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
|
|
||||||
struct score best = {{0}, {0}, {0}, 0};
|
|
||||||
|
|
||||||
start_x = field->p0.x;
|
|
||||||
end_x = field->p1.x;
|
|
||||||
start_y = field->p0.y;
|
|
||||||
end_y = field->p1.y;
|
|
||||||
|
|
||||||
/* check scan area co-ordinates */
|
|
||||||
if (field->p1.x < field->p0.x ||
|
|
||||||
field->p1.y < field->p0.y)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* check if allocation would fit in scan area */
|
|
||||||
if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
start_x = ALIGN(start_x, align);
|
|
||||||
|
|
||||||
/* check if allocation would still fit in scan area */
|
|
||||||
if (w > LEN(end_x, start_x))
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
/* adjust end_x and end_y, as allocation would not fit beyond */
|
|
||||||
end_x = end_x - w + 1; /* + 1 to be inclusive */
|
|
||||||
end_y = end_y - h + 1;
|
|
||||||
|
|
||||||
/* scan field top-to-bottom, left-to-right */
|
|
||||||
for (y = start_y; y <= end_y; y++) {
|
|
||||||
for (x = start_x; x <= end_x; x += align) {
|
|
||||||
if (is_area_free(map, x, y, w, h)) {
|
|
||||||
found_x = x;
|
|
||||||
|
|
||||||
/* update best candidate */
|
|
||||||
if (update_candidate(tcm, x, y, w, h, field,
|
|
||||||
CR_L2R_T2B, &best))
|
|
||||||
goto done;
|
|
||||||
/* change upper x bound */
|
|
||||||
end_x = x - 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else if (map[x][y] && map[x][y]->is2d) {
|
|
||||||
/* step over 2D areas */
|
|
||||||
x = ALIGN_DOWN(map[x][y]->p1.x, align);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* break if you find a free area shouldering the scan field */
|
|
||||||
if (found_x == start_x)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!best.a.tcm)
|
|
||||||
return -ENOSPC;
|
|
||||||
done:
|
|
||||||
assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raster scan horizontally right to left from bottom to top to find a place
|
|
||||||
* for a 1D area of given size inside a scan field.
|
|
||||||
*
|
|
||||||
* @param num_slots size of desired area
|
|
||||||
* @param align desired area alignment
|
|
||||||
* @param area pointer to the area that will be set to the best
|
|
||||||
* position
|
|
||||||
* @param field area to scan (inclusive)
|
|
||||||
*
|
|
||||||
* @return 0 on success, non-0 error value on failure.
|
|
||||||
*/
|
|
||||||
static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
|
|
||||||
struct tcm_area *field, struct tcm_area *area)
|
|
||||||
{
|
|
||||||
s32 found = 0;
|
|
||||||
s16 x, y;
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
struct tcm_area *p;
|
|
||||||
|
|
||||||
/* check scan area co-ordinates */
|
|
||||||
if (field->p0.y < field->p1.y)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Currently we only support full width 1D scan field, which makes sense
|
|
||||||
* since 1D slot-ordering spans the full container width.
|
|
||||||
*/
|
|
||||||
if (tcm->width != field->p0.x - field->p1.x + 1)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* check if allocation would fit in scan area */
|
|
||||||
if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y))
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
x = field->p0.x;
|
|
||||||
y = field->p0.y;
|
|
||||||
|
|
||||||
/* find num_slots consecutive free slots to the left */
|
|
||||||
while (found < num_slots) {
|
|
||||||
if (y < 0)
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
/* remember bottom-right corner */
|
|
||||||
if (found == 0) {
|
|
||||||
area->p1.x = x;
|
|
||||||
area->p1.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip busy regions */
|
|
||||||
p = pvt->map[x][y];
|
|
||||||
if (p) {
|
|
||||||
/* move to left of 2D areas, top left of 1D */
|
|
||||||
x = p->p0.x;
|
|
||||||
if (!p->is2d)
|
|
||||||
y = p->p0.y;
|
|
||||||
|
|
||||||
/* start over */
|
|
||||||
found = 0;
|
|
||||||
} else {
|
|
||||||
/* count consecutive free slots */
|
|
||||||
found++;
|
|
||||||
if (found == num_slots)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* move to the left */
|
|
||||||
if (x == 0)
|
|
||||||
y--;
|
|
||||||
x = (x ? : tcm->width) - 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set top-left corner */
|
|
||||||
area->p0.x = x;
|
|
||||||
area->p0.y = y;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a place for a 2D area of given size inside a scan field based on its
|
|
||||||
* alignment needs.
|
|
||||||
*
|
|
||||||
* @param w width of desired area
|
|
||||||
* @param h height of desired area
|
|
||||||
* @param align desired area alignment
|
|
||||||
* @param area pointer to the area that will be set to the best position
|
|
||||||
*
|
|
||||||
* @return 0 on success, non-0 error value on failure.
|
|
||||||
*/
|
|
||||||
static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
|
|
||||||
struct tcm_area *area)
|
|
||||||
{
|
|
||||||
s32 ret = 0;
|
|
||||||
struct tcm_area field = {0};
|
|
||||||
u16 boundary_x, boundary_y;
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
|
|
||||||
if (align > 1) {
|
|
||||||
/* prefer top-left corner */
|
|
||||||
boundary_x = pvt->div_pt.x - 1;
|
|
||||||
boundary_y = pvt->div_pt.y - 1;
|
|
||||||
|
|
||||||
/* expand width and height if needed */
|
|
||||||
if (w > pvt->div_pt.x)
|
|
||||||
boundary_x = tcm->width - 1;
|
|
||||||
if (h > pvt->div_pt.y)
|
|
||||||
boundary_y = tcm->height - 1;
|
|
||||||
|
|
||||||
assign(&field, 0, 0, boundary_x, boundary_y);
|
|
||||||
ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
|
|
||||||
|
|
||||||
/* scan whole container if failed, but do not scan 2x */
|
|
||||||
if (ret != 0 && (boundary_x != tcm->width - 1 ||
|
|
||||||
boundary_y != tcm->height - 1)) {
|
|
||||||
/* scan the entire container if nothing found */
|
|
||||||
assign(&field, 0, 0, tcm->width - 1, tcm->height - 1);
|
|
||||||
ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
|
|
||||||
}
|
|
||||||
} else if (align == 1) {
|
|
||||||
/* prefer top-right corner */
|
|
||||||
boundary_x = pvt->div_pt.x;
|
|
||||||
boundary_y = pvt->div_pt.y - 1;
|
|
||||||
|
|
||||||
/* expand width and height if needed */
|
|
||||||
if (w > (tcm->width - pvt->div_pt.x))
|
|
||||||
boundary_x = 0;
|
|
||||||
if (h > pvt->div_pt.y)
|
|
||||||
boundary_y = tcm->height - 1;
|
|
||||||
|
|
||||||
assign(&field, tcm->width - 1, 0, boundary_x, boundary_y);
|
|
||||||
ret = scan_r2l_t2b(tcm, w, h, align, &field, area);
|
|
||||||
|
|
||||||
/* scan whole container if failed, but do not scan 2x */
|
|
||||||
if (ret != 0 && (boundary_x != 0 ||
|
|
||||||
boundary_y != tcm->height - 1)) {
|
|
||||||
/* scan the entire container if nothing found */
|
|
||||||
assign(&field, tcm->width - 1, 0, 0, tcm->height - 1);
|
|
||||||
ret = scan_r2l_t2b(tcm, w, h, align, &field,
|
|
||||||
area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check if an entire area is free */
|
|
||||||
static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h)
|
|
||||||
{
|
|
||||||
u16 x = 0, y = 0;
|
|
||||||
for (y = y0; y < y0 + h; y++) {
|
|
||||||
for (x = x0; x < x0 + w; x++) {
|
|
||||||
if (map[x][y])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fills an area with a parent tcm_area */
|
|
||||||
static void fill_area(struct tcm *tcm, struct tcm_area *area,
|
|
||||||
struct tcm_area *parent)
|
|
||||||
{
|
|
||||||
s32 x, y;
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
struct tcm_area a, a_;
|
|
||||||
|
|
||||||
/* set area's tcm; otherwise, enumerator considers it invalid */
|
|
||||||
area->tcm = tcm;
|
|
||||||
|
|
||||||
tcm_for_each_slice(a, *area, a_) {
|
|
||||||
for (x = a.p0.x; x <= a.p1.x; ++x)
|
|
||||||
for (y = a.p0.y; y <= a.p1.y; ++y)
|
|
||||||
pvt->map[x][y] = parent;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares a candidate area to the current best area, and if it is a better
|
|
||||||
* fit, it updates the best to this one.
|
|
||||||
*
|
|
||||||
* @param x0, y0, w, h top, left, width, height of candidate area
|
|
||||||
* @param field scan field
|
|
||||||
* @param criteria scan criteria
|
|
||||||
* @param best best candidate and its scores
|
|
||||||
*
|
|
||||||
* @return 1 (true) if the candidate area is known to be the final best, so no
|
|
||||||
* more searching should be performed
|
|
||||||
*/
|
|
||||||
static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
|
|
||||||
struct tcm_area *field, s32 criteria,
|
|
||||||
struct score *best)
|
|
||||||
{
|
|
||||||
struct score me; /* score for area */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: For horizontal bias we always give the first found, because our
|
|
||||||
* scan is horizontal-raster-based and the first candidate will always
|
|
||||||
* have the horizontal bias.
|
|
||||||
*/
|
|
||||||
bool first = criteria & CR_BIAS_HORIZONTAL;
|
|
||||||
|
|
||||||
assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1);
|
|
||||||
|
|
||||||
/* calculate score for current candidate */
|
|
||||||
if (!first) {
|
|
||||||
get_neighbor_stats(tcm, &me.a, &me.n);
|
|
||||||
me.neighs = me.n.edge + me.n.busy;
|
|
||||||
get_nearness_factor(field, &me.a, &me.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the 1st candidate is always the best */
|
|
||||||
if (!best->a.tcm)
|
|
||||||
goto better;
|
|
||||||
|
|
||||||
BUG_ON(first);
|
|
||||||
|
|
||||||
/* diagonal balance check */
|
|
||||||
if ((criteria & CR_DIAGONAL_BALANCE) &&
|
|
||||||
best->neighs <= me.neighs &&
|
|
||||||
(best->neighs < me.neighs ||
|
|
||||||
/* this implies that neighs and occupied match */
|
|
||||||
best->n.busy < me.n.busy ||
|
|
||||||
(best->n.busy == me.n.busy &&
|
|
||||||
/* check the nearness factor */
|
|
||||||
best->f.x + best->f.y > me.f.x + me.f.y)))
|
|
||||||
goto better;
|
|
||||||
|
|
||||||
/* not better, keep going */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
better:
|
|
||||||
/* save current area as best */
|
|
||||||
memcpy(best, &me, sizeof(me));
|
|
||||||
best->a.tcm = tcm;
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the nearness factor of an area in a search field. The nearness
|
|
||||||
* factor is smaller if the area is closer to the search origin.
|
|
||||||
*/
|
|
||||||
static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area,
|
|
||||||
struct nearness_factor *nf)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Using signed math as field coordinates may be reversed if
|
|
||||||
* search direction is right-to-left or bottom-to-top.
|
|
||||||
*/
|
|
||||||
nf->x = (s32)(area->p0.x - field->p0.x) * 1000 /
|
|
||||||
(field->p1.x - field->p0.x);
|
|
||||||
nf->y = (s32)(area->p0.y - field->p0.y) * 1000 /
|
|
||||||
(field->p1.y - field->p0.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get neighbor statistics */
|
|
||||||
static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
|
|
||||||
struct neighbor_stats *stat)
|
|
||||||
{
|
|
||||||
s16 x = 0, y = 0;
|
|
||||||
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
|
|
||||||
|
|
||||||
/* Clearing any exisiting values */
|
|
||||||
memset(stat, 0, sizeof(*stat));
|
|
||||||
|
|
||||||
/* process top & bottom edges */
|
|
||||||
for (x = area->p0.x; x <= area->p1.x; x++) {
|
|
||||||
if (area->p0.y == 0)
|
|
||||||
stat->edge++;
|
|
||||||
else if (pvt->map[x][area->p0.y - 1])
|
|
||||||
stat->busy++;
|
|
||||||
|
|
||||||
if (area->p1.y == tcm->height - 1)
|
|
||||||
stat->edge++;
|
|
||||||
else if (pvt->map[x][area->p1.y + 1])
|
|
||||||
stat->busy++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process left & right edges */
|
|
||||||
for (y = area->p0.y; y <= area->p1.y; ++y) {
|
|
||||||
if (area->p0.x == 0)
|
|
||||||
stat->edge++;
|
|
||||||
else if (pvt->map[area->p0.x - 1][y])
|
|
||||||
stat->busy++;
|
|
||||||
|
|
||||||
if (area->p1.x == tcm->width - 1)
|
|
||||||
stat->edge++;
|
|
||||||
else if (pvt->map[area->p1.x + 1][y])
|
|
||||||
stat->busy++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -61,18 +61,17 @@ struct tcm {
|
|||||||
|
|
||||||
unsigned int y_offset; /* offset to use for y coordinates */
|
unsigned int y_offset; /* offset to use for y coordinates */
|
||||||
|
|
||||||
/* 'pvt' structure shall contain any tcm details (attr) along with
|
spinlock_t lock;
|
||||||
linked list of allocated areas and mutex for mutually exclusive access
|
unsigned long *bitmap;
|
||||||
to the list. It may also contain copies of width and height to notice
|
size_t map_size;
|
||||||
any changes to the publicly available width and height fields. */
|
|
||||||
void *pvt;
|
|
||||||
|
|
||||||
/* function table */
|
/* function table */
|
||||||
s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u8 align,
|
s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align,
|
||||||
|
int16_t offset, uint16_t slot_bytes,
|
||||||
struct tcm_area *area);
|
struct tcm_area *area);
|
||||||
s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
|
s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
|
||||||
s32 (*free) (struct tcm *tcm, struct tcm_area *area);
|
s32 (*free)(struct tcm *tcm, struct tcm_area *area);
|
||||||
void (*deinit) (struct tcm *tcm);
|
void (*deinit)(struct tcm *tcm);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*=============================================================================
|
/*=============================================================================
|
||||||
@ -91,7 +90,7 @@ struct tcm {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr);
|
struct tcm *sita_init(u16 width, u16 height);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,6 +119,9 @@ static inline void tcm_deinit(struct tcm *tcm)
|
|||||||
* all values may be supported by the container manager,
|
* all values may be supported by the container manager,
|
||||||
* but it must support 0 (1), 32 and 64.
|
* but it must support 0 (1), 32 and 64.
|
||||||
* 0 value is equivalent to 1.
|
* 0 value is equivalent to 1.
|
||||||
|
* @param offset Offset requirement, in bytes. This is the offset
|
||||||
|
* from a 4KiB aligned virtual address.
|
||||||
|
* @param slot_bytes Width of slot in bytes
|
||||||
* @param area Pointer to where the reserved area should be stored.
|
* @param area Pointer to where the reserved area should be stored.
|
||||||
*
|
*
|
||||||
* @return 0 on success. Non-0 error code on failure. Also,
|
* @return 0 on success. Non-0 error code on failure. Also,
|
||||||
@ -129,7 +131,8 @@ static inline void tcm_deinit(struct tcm *tcm)
|
|||||||
* allocation.
|
* allocation.
|
||||||
*/
|
*/
|
||||||
static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
|
static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
|
||||||
u16 align, struct tcm_area *area)
|
u16 align, int16_t offset, uint16_t slot_bytes,
|
||||||
|
struct tcm_area *area)
|
||||||
{
|
{
|
||||||
/* perform rudimentary error checking */
|
/* perform rudimentary error checking */
|
||||||
s32 res = tcm == NULL ? -ENODEV :
|
s32 res = tcm == NULL ? -ENODEV :
|
||||||
@ -140,7 +143,8 @@ static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
|
|||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
area->is2d = true;
|
area->is2d = true;
|
||||||
res = tcm->reserve_2d(tcm, height, width, align, area);
|
res = tcm->reserve_2d(tcm, height, width, align, offset,
|
||||||
|
slot_bytes, area);
|
||||||
area->tcm = res ? NULL : tcm;
|
area->tcm = res ? NULL : tcm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user