aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLajos Molnar <molnar@ti.com>2011-12-16 14:10:51 +0800
committerAndy Green <andy.green@linaro.org>2011-12-26 22:33:13 +0800
commit7ca2bdfb019bd86a8be4f5d6470b68348ccfb0e0 (patch)
treed2c6f12b088029b017536f2f320e50f4cc3d8dbb
parent936ed08e9a38647179290f8fa160d1d606217a48 (diff)
TILER: TCM-SiTA: Combined fill_1d/2d_area
We can treat 1d and 2d areas uniformly using the tcm_for_each_slice macro. Signed-off-by: Lajos Molnar <molnar@ti.com> Signed-off-by: David Sin <davidsin@ti.com> TILER: TCM-SiTA: Cleaned up tcm_sita code and fixed 1D allocation. Cleaned up comments. Improved optimization for skipping blocks while searching. Rewrote 1D scan algorithm. This is now significantly simpler and to the point, and it also fixed potential incorrect x, y value if the tiler is completely full. Removed unused methods/values, and shortened some unnecessarily long variable names. Signed-off-by: Lajos Molnar <molnar@ti.com> Signed-off-by: David Sin <davidsin@ti.com> TILER: TCM-SiTA: Remove unnecessary copy of width and height tcm struct already contains width and height, and there is no need to copy it into the private data. Signed-off-by: Lajos Molnar <molnar@ti.com> Signed-off-by: David Sin <davidsin@ti.com> TILER: TCM-SiTA: Simplified scanning code and neighbor stats Only combined neighbor stats are used by algorithm, so we now calculate combined stats. Now passing map to is_area_clear. Also, is_area_clear starts by checking top left corner, so checking whether it is busy is redundant. Removed done variable from scan, and instead exit loop directly. Signed-off-by: Lajos Molnar <molnar@ti.com> Signed-off-by: David Sin <davidsin@ti.com>
-rw-r--r--drivers/media/video/tiler/tcm/_tcm-sita.h76
-rw-r--r--drivers/media/video/tiler/tcm/tcm-sita.c1075
-rw-r--r--drivers/media/video/tiler/tcm/tcm-sita.h4
3 files changed, 415 insertions, 740 deletions
diff --git a/drivers/media/video/tiler/tcm/_tcm-sita.h b/drivers/media/video/tiler/tcm/_tcm-sita.h
index 9b8992a3bb5..a300b923ef0 100644
--- a/drivers/media/video/tiler/tcm/_tcm-sita.h
+++ b/drivers/media/video/tiler/tcm/_tcm-sita.h
@@ -16,78 +16,50 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#ifndef _TCM_SITA_H_
-#define _TCM_SITA_H_
+#ifndef _TCM_SITA_H
+#define _TCM_SITA_H
#include "../tcm.h"
-#define TL_CORNER 0
-#define TR_CORNER 1
-#define BL_CORNER 3
-#define BR_CORNER 4
+/* length between two coordinates */
+#define LEN(a, b) ((a) > (b) ? (a) - (b) + 1 : (b) - (a) + 1)
-/*Provide inclusive length between co-ordinates */
-#define INCL_LEN(high, low) ((high) - (low) + 1)
-#define INCL_LEN_MOD(start, end) ((start) > (end) ? (start) - (end) + 1 : \
- (end) - (start) + 1)
-
-#define BOUNDARY(stat) ((stat)->top_boundary + (stat)->bottom_boundary + \
- (stat)->left_boundary + (stat)->right_boundary)
-#define OCCUPIED(stat) ((stat)->top_occupied + (stat)->bottom_occupied + \
- (stat)->left_occupied + (stat)->right_occupied)
-
-enum Criteria {
- CR_MAX_NEIGHS = 0x01,
- CR_FIRST_FOUND = 0x10,
- CR_BIAS_HORIZONTAL = 0x20,
- CR_BIAS_VERTICAL = 0x40,
- CR_DIAGONAL_BALANCE = 0x80
+enum criteria {
+ CR_MAX_NEIGHS = 0x01,
+ CR_FIRST_FOUND = 0x10,
+ CR_BIAS_HORIZONTAL = 0x20,
+ CR_BIAS_VERTICAL = 0x40,
+ CR_DIAGONAL_BALANCE = 0x80
};
+/* nearness to the beginning of the search field from 0 to 1000 */
struct nearness_factor {
s32 x;
s32 y;
};
/*
- * Area info kept
+ * Statistics on immediately neighboring slots. Edge is the number of
+ * border segments that are also border segments of the scan field. Busy
+ * refers to the number of neighbors that are occupied.
*/
-struct area_spec {
- struct tcm_area area;
- struct list_head list;
-};
-
-/*
- * Everything is a rectangle with four sides and on
- * each side you could have a boundary or another Tile.
- * The tile could be Occupied or Not. These info is stored
- */
-struct neighbour_stats {
- u16 left_boundary;
- u16 left_occupied;
- u16 top_boundary;
- u16 top_occupied;
- u16 right_boundary;
- u16 right_occupied;
- u16 bottom_boundary;
- u16 bottom_occupied;
+struct neighbor_stats {
+ u16 edge;
+ u16 busy;
};
+/* structure to keep the score of a potential allocation */
struct score {
- struct nearness_factor f;
- struct neighbour_stats n;
- struct tcm_area a;
- u16 neighs;
+ struct nearness_factor f;
+ struct neighbor_stats n;
+ struct tcm_area a;
+ u16 neighs; /* number of busy neighbors */
};
-
struct sita_pvt {
- u16 width;
- u16 height;
struct mutex mtx;
struct tcm_pt div_pt; /* divider point splitting container */
- /* container slots - simply pointers to parent area */
- struct tcm_area ***map;
+ struct tcm_area ***map; /* pointers to the parent area for each slot */
};
-#endif /* _TCM_SITA_H_ */
+#endif
diff --git a/drivers/media/video/tiler/tcm/tcm-sita.c b/drivers/media/video/tiler/tcm/tcm-sita.c
index ba1ff5f57d0..94902b7afa6 100644
--- a/drivers/media/video/tiler/tcm/tcm-sita.c
+++ b/drivers/media/video/tiler/tcm/tcm-sita.c
@@ -1,10 +1,11 @@
/*
* tcm-sita.c
*
- * Author: Ravi Ramachandra <r.ramachandra@ti.com>
- *
* SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
*
+ * Authors: Ravi Ramachandra <r.ramachandra@ti.com>,
+ * Lajos Molnar <molnar@ti.com>
+ *
* Copyright (C) 2009-2010 Texas Instruments, Inc.
*
* This package is free software; you can redistribute it and/or modify
@@ -41,110 +42,66 @@ static s32 CR_L2R_B2T = CR_DIAGONAL_BALANCE;
* 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 *to_be_removed_area);
+ 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);
/*********************************************
* Main Scanner functions
*********************************************/
-static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 stride,
+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 stride,
+static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
struct tcm_area *field, struct tcm_area *area);
-static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 stride,
+static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
struct tcm_area *field, struct tcm_area *area);
#ifdef SCAN_BOTTOM_UP
-static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
+static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
struct tcm_area *field, struct tcm_area *area);
-static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
+static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
struct tcm_area *field, struct tcm_area *area);
#endif
-static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_pages,
+static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
struct tcm_area *field, struct tcm_area *area);
/*********************************************
* Support Infrastructure Methods
*********************************************/
-static s32 check_fit_r_and_b(struct tcm *tcm, u16 w, u16 h, u16 left_x,
- u16 top_y);
-
-static s32 check_fit_r_one_dim(struct tcm *tcm, u16 x, u16 y, u32 num_pages,
- u16 *busy_x, u16 *busy_y);
+static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
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 tcm_area *field, s32 criteria,
+ struct score *best);
static void get_nearness_factor(struct tcm_area *field,
- struct tcm_area *candidate, struct nearness_factor *nf);
-
-static s32 get_busy_neigh_stats(struct tcm *tcm, u16 width, u16 height,
- struct tcm_area *top_left_corner,
- struct neighbour_stats *neighbour_stat);
+ struct tcm_area *candidate,
+ struct nearness_factor *nf);
-static void fill_1d_area(struct tcm *tcm,
- struct tcm_area *area, struct tcm_area *parent);
+static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
+ struct neighbor_stats *stat);
-static void fill_2d_area(struct tcm *tcm,
- struct tcm_area *area, struct tcm_area *parent);
+static void fill_area(struct tcm *tcm,
+ struct tcm_area *area, struct tcm_area *parent);
-static s32 move_left(struct tcm *tcm, u16 x, u16 y, u32 num_pages,
- u16 *xx, u16 *yy);
-static s32 move_right(struct tcm *tcm, u16 x, u16 y, u32 num_pages,
- u16 *xx, u16 *yy);
/*********************************************/
/*********************************************
* Utility Methods
*********************************************/
-
-#if 0
-static
-void dump_list_entries(struct list_head *head)
-{
- struct area_spec *elem = NULL;
-
- P1("Printing List Entries:\n");
-
- list_for_each_entry(elem, head, list) {
- printk(KERN_NOTICE "%dD:" AREA_FMT "\n", elem->area.type,
- AREA(elem->area));
- }
-
- P1("List Finished\n");
-}
-
-static
-s32 dump_neigh_stats(struct neighbour_stats *neighbour)
-{
- P1("Top Occ:Boundary %d:%d\n", neighbour->top_occupied,
- neighbour->top_boundary);
- P1("Bot Occ:Boundary %d:%d\n", neighbour->bottom_occupied,
- neighbour->bottom_boundary);
- P1("Left Occ:Boundary %d:%d\n", neighbour->left_occupied,
- neighbour->left_boundary);
- P1("Rigt Occ:Boundary %d:%d\n", neighbour->right_occupied,
- neighbour->right_boundary);
- return 0;
-}
-#endif
-
struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
{
- struct tcm *tcm = NULL;
- struct sita_pvt *pvt = NULL;
+ struct tcm *tcm;
+ struct sita_pvt *pvt;
struct tcm_area area = {0};
- s32 i = 0;
+ s32 i;
if (width == 0 || height == 0)
- goto error;
+ return NULL;
tcm = kmalloc(sizeof(*tcm), GFP_KERNEL);
pvt = kmalloc(sizeof(*pvt), GFP_KERNEL);
@@ -163,20 +120,16 @@ struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
tcm->deinit = sita_deinit;
tcm->pvt = (void *)pvt;
- pvt->height = height;
- pvt->width = width;
-
mutex_init(&(pvt->mtx));
/* Creating tam map */
- pvt->map = kmalloc(sizeof(*pvt->map) * pvt->width, GFP_KERNEL);
-
+ pvt->map = kmalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
if (!pvt->map)
goto error;
- for (i = 0; i < pvt->width; i++) {
+ for (i = 0; i < tcm->width; i++) {
pvt->map[i] =
- kmalloc(sizeof(**pvt->map) * pvt->height,
+ kmalloc(sizeof(**pvt->map) * tcm->height,
GFP_KERNEL);
if (pvt->map[i] == NULL) {
while (i--)
@@ -186,22 +139,20 @@ struct tcm *sita_init(u16 width, u16 height, struct tcm_pt *attr)
}
}
- if (attr && attr->x <= pvt->width && attr->y <= pvt->height) {
+ 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 = (pvt->width * 3) / 4;
- pvt->div_pt.y = (pvt->height * 3) / 4;
+ pvt->div_pt.x = (tcm->width * 3) / 4;
+ pvt->div_pt.y = (tcm->height * 3) / 4;
}
- area.p1.x = width - 1;
- area.p1.y = height - 1;
-
mutex_lock(&(pvt->mtx));
- fill_2d_area(tcm, &area, NULL);
+ assign(&area, 0, 0, width - 1, height - 1);
+ fill_area(tcm, &area, NULL);
mutex_unlock(&(pvt->mtx));
return tcm;
@@ -213,116 +164,95 @@ error:
static void sita_deinit(struct tcm *tcm)
{
- struct sita_pvt *pvt = NULL;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
struct tcm_area area = {0};
- s32 i = 0;
+ s32 i;
- pvt = (struct sita_pvt *)tcm->pvt;
- if (pvt) {
- area.p1.x = pvt->width - 1;
- area.p1.y = pvt->height - 1;
+ area.p1.x = tcm->width - 1;
+ area.p1.y = tcm->height - 1;
- mutex_lock(&(pvt->mtx));
- fill_2d_area(tcm, &area, NULL);
- mutex_unlock(&(pvt->mtx));
+ mutex_lock(&(pvt->mtx));
+ fill_area(tcm, &area, NULL);
+ mutex_unlock(&(pvt->mtx));
- mutex_destroy(&(pvt->mtx));
+ mutex_destroy(&(pvt->mtx));
- for (i = 0; i < pvt->height; i++) {
- kfree(pvt->map[i]);
- pvt->map[i] = NULL;
- }
- kfree(pvt->map);
- pvt->map = NULL;
- kfree(pvt);
- }
+ for (i = 0; i < tcm->height; i++)
+ kfree(pvt->map[i]);
+ kfree(pvt->map);
+ kfree(pvt);
}
/**
- * @description: Allocate 1d pages if the required number of pages are
- * available in the container
+ * Reserve a 1D area in the container
*
- * @input:num_pages to be allocated
+ * @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. On success
- * area contain co-ordinates of start and end Tiles(inclusive)
+ * @return 0 on success, non-0 error value on failure.
*/
-static s32 sita_reserve_1d(struct tcm *tcm, u32 num_pages,
+static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
struct tcm_area *area)
{
- s32 ret = 0;
+ s32 ret;
struct tcm_area field = {0};
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- area->is2d = false;
-
mutex_lock(&(pvt->mtx));
#ifdef RESTRICT_1D
/* scan within predefined 1D boundary */
- assign(&field, pvt->width - 1, pvt->height - 1, 0, pvt->div_pt.y);
+ assign(&field, tcm->width - 1, tcm->height - 1, 0, pvt->div_pt.y);
#else
/* Scanning entire container */
- assign(&field, pvt->width - 1, pvt->height - 1, 0, 0);
+ assign(&field, tcm->width - 1, tcm->height - 1, 0, 0);
#endif
- ret = scan_r2l_b2t_one_dim(tcm, num_pages,
- &field, area);
- /* There is not much to select, we pretty much give the first one
- which accomodates */
+ ret = scan_r2l_b2t_one_dim(tcm, num_slots, &field, area);
if (!ret)
/* update map */
- fill_1d_area(tcm, area, area);
- else
- /* otherwise, invalidate area */
- area->tcm = NULL;
+ fill_area(tcm, area, area);
mutex_unlock(&(pvt->mtx));
return ret;
}
/**
- * @description: Allocate 2d area on availability in the container
+ * Reserve a 2D area in the container
*
- * @input:'w'idth and 'h'eight of the 2d area, 'align'ment specification
+ * @param w width
+ * @param h height
+ * @param area pointer to the area that will be populated with the reesrved
+ * area
*
- * @return 0 on success, non-0 error value on failure. On success
- * area contain co-ordinates of TL corner Tile and BR corner Tile of
- * the rectangle (inclusive)
+ * @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 = 0;
+ s32 ret;
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- /* we only support 1, 32 and 64 as alignment */
- u16 stride = align <= 1 ? 1 : align <= 32 ? 32 : 64;
- area->is2d = true;
-
- /* align must be 2 power */
- if (align & (align - 1) || align > 64)
+ /* 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;
+
mutex_lock(&(pvt->mtx));
- ret = scan_areas_and_find_fit(tcm, w, h, stride, area);
+ ret = scan_areas_and_find_fit(tcm, w, h, align, area);
if (!ret)
/* update map */
- fill_2d_area(tcm, area, area);
- else
- /* otherwise, invalidate area */
- area->tcm = NULL;
+ fill_area(tcm, area, area);
mutex_unlock(&(pvt->mtx));
return ret;
}
/**
- * @description: unreserve a previously allocated 2d or 1D allocation
- *
- * @input:'area' specification: for 2D this should contain
- * TL Corner and BR Corner of the 2D area, or for 1D allocation this should
- * contain the start and end Tiles
- *
- * The tiles corresponding to the area are marked 'NOT_OCCUPIED'
+ * 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)
{
@@ -335,10 +265,7 @@ static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
pvt->map[area->p1.x][area->p1.y] != area);
/* Clear the contents of the associated tiles in the map */
- if (area->is2d)
- fill_2d_area(tcm, area, NULL);
- else
- fill_1d_area(tcm, area, NULL);
+ fill_area(tcm, area, NULL);
mutex_unlock(&(pvt->mtx));
@@ -346,26 +273,31 @@ static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
}
/**
- * @description: raster scan right to left from top to bottom; find if there is
- * a free area to fit a given w x h inside the 'scan area'. If there is a free
- * area, then adds to maybes candidates, which later is sent for selection
- * as per pre-defined criteria.
- *
- * @input:'w x h' width and height of the allocation area.
- * 'stride' - 64/32/None for start address alignment
- * 'field' - area in which the scan operation should take place
+ * 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.
*
- * @return 0 on success, non-0 error value on failure. On success
- * the 'area' area contains TL and BR corners of the allocated area
+ * @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 stride,
- struct tcm_area *field, struct tcm_area *area)
+static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
{
- s32 xx = 0, yy = 0, done = 0;
- s16 start_x = -1, end_x = -1, start_y = -1, end_y = -1;
- s16 found_x = -1, found_y = -1;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ 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};
PA(2, "scan_r2l_t2b:", field);
@@ -381,58 +313,44 @@ static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 stride,
return -EINVAL;
/* check if allocation would fit in scan area */
- if (w > INCL_LEN(start_x, end_x) || h > INCL_LEN(end_y, start_y))
+ 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, stride); /* - 1 to be inclusive */
+ 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;
- P2("ali=%d x=%d..%d y=%d..%d", stride, start_x, end_x, start_y, end_y);
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
- /*
- * Start scanning: These scans are always inclusive ones so if we are
- * given a start x = 0 is a valid value so if we have a end_x = 255,
- * 255th element is also checked
- */
- for (yy = start_y; yy <= end_y && !done; yy++) {
- for (xx = start_x; xx >= end_x; xx -= stride) {
- if (!pvt->map[xx][yy]) {
- if (check_fit_r_and_b(tcm, w, h, xx, yy)) {
- P3("found shoulder: %d,%d", xx, yy);
- found_x = xx;
- found_y = yy;
- /* Insert this candidate, it is just a
- co-ordinate, reusing Area */
- done = update_candidate(tcm, xx, yy, w,
- h, field, CR_R2L_T2B, &best);
- if (done)
- break;
+ /* 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)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_R2L_T2B, &best))
+ goto done;
#ifdef X_SCAN_LIMITER
- /* change upper x bound */
- end_x = xx + 1;
+ /* change upper x bound */
+ end_x = x + 1;
#endif
- break;
- }
- } else {
- /* Optimization required only for Non Aligned,
- Aligned anyways skip by 32/64 tiles at a time */
- if (stride == 1 &&
- pvt->map[xx][yy]->is2d) {
- xx = pvt->map[xx][yy]->p0.x;
- P3("moving to: %d,%d", xx, yy);
- }
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN(map[x][y]->p0.x - w + 1, align);
+ P3("moving to: %d,%d", x, y);
}
}
-
- /* if you find a free area shouldering the given scan area on
- then we can break */
#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
if (found_x == start_x)
break;
#endif
@@ -440,36 +358,33 @@ static s32 scan_r2l_t2b(struct tcm *tcm, u16 w, u16 h, u16 stride,
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;
}
#ifdef SCAN_BOTTOM_UP
/**
- * @description: raster scan right to left from bottom to top; find if there is
- * a free area to fit a given w x h inside the 'scan area'. If there is a free
- * area, then adds to maybes candidates, which later is sent for selection
- * as per pre-defined criteria.
- *
- * @input:'w x h' width and height of the allocation area.
- * 'stride' - 64/32/None for start address alignment
- * 'field' - area in which the scan operation should take place
+ * Raster scan horizontally right to left from bottom to top to find a place
+ * for a 2D area of given size inside a scan field.
*
- * @return 0 on success, non-0 error value on failure. On success
- * the 'area' area contains TL and BR corners of the allocated area
+ * @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_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
+static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
struct tcm_area *field, struct tcm_area *area)
{
/* TODO: Should I check scan area?
* Might have to take it as input during initialization
*/
- s32 xx = 0, yy = 0, done = 0;
- s16 start_x = -1, end_x = -1, start_y = -1, end_y = -1;
- s16 found_x = -1, found_y = -1;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ 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};
PA(2, "scan_r2l_b2t:", field);
@@ -485,58 +400,43 @@ static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
return -EINVAL;
/* check if allocation would fit in scan area */
- if (w > INCL_LEN(start_x, end_x) || h > INCL_LEN(start_y, end_y))
+ if (w > LEN(start_x, end_x) || h > LEN(start_y, end_y))
return -ENOSPC;
/* adjust start_x and start_y, as allocation would not fit beyond */
- start_x = ALIGN_DOWN(start_x - w + 1, stride); /* + 1 to be inclusive */
+ start_x = ALIGN_DOWN(start_x - w + 1, align); /* + 1 to be inclusive */
start_y = start_y - h + 1;
/* check if allocation would still fit in scan area */
if (start_x < end_x)
return -ENOSPC;
- P2("ali=%d x=%d..%d y=%d..%d", stride, start_x, end_x, start_y, end_y);
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
- /*
- * Start scanning: These scans are always inclusive ones so if we are
- * given a start x = 0 is a valid value so if we have a end_x = 255,
- * 255th element is also checked
- */
- for (yy = start_y; yy >= end_y && !done; yy--) {
- for (xx = start_x; xx >= end_x; xx -= stride) {
- if (!pvt->map[xx][yy]) {
- if (check_fit_r_and_b(tcm, w, h, xx, yy)) {
- P3("found shoulder: %d,%d", xx, yy);
- found_x = xx;
- found_y = yy;
- /* Insert this candidate, it is just a
- co-ordinate, reusing Area */
- done = update_candidate(tcm, xx, yy, w,
- h, field, CR_R2L_B2T, &best);
- if (done)
- break;
+ /* scan field bottom-to-top, 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)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_R2L_B2T, &best))
+ goto done;
#ifdef X_SCAN_LIMITER
- /* change upper x bound */
- end_x = xx + 1;
+ /* change upper x bound */
+ end_x = x + 1;
#endif
- break;
- }
- } else {
- /* Optimization required only for Non Aligned,
- Aligned anyways skip by 32/64 tiles at a time */
- if (stride == 1 &&
- pvt->map[xx][yy]->is2d) {
- xx = pvt->map[xx][yy]->p0.x;
- P3("moving to: %d,%d", xx, yy);
- }
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN(map[x][y]->p0.x - w + 1, align);
+ P3("moving to: %d,%d", x, y);
}
-
}
-
- /* if you find a free area shouldering the given scan area on
- then we can break */
#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
if (found_x == start_x)
break;
#endif
@@ -544,33 +444,30 @@ static s32 scan_r2l_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
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;
}
#endif
/**
- * @description: raster scan left to right from top to bottom; find if there is
- * a free area to fit a given w x h inside the 'scan area'. If there is a free
- * area, then adds to maybes candidates, which later is sent for selection
- * as per pre-defined criteria.
- *
- * @input:'w x h' width and height of the allocation area.
- * 'stride' - 64/32/None for start address alignment
- * 'field' - area in which the scan operation should take place
+ * 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.
*
- * @return 0 on success, non-0 error value on failure. On success
- * the 'area' area contains TL and BR corners of the allocated area
+ * @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.
*/
-s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 stride,
- struct tcm_area *field, struct tcm_area *area)
+static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
{
- s32 xx = 0, yy = 0, done = 0;
- s16 start_x = -1, end_x = -1, start_y = -1, end_y = -1;
- s16 found_x = -1, found_y = -1;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ 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};
PA(2, "scan_l2r_t2b:", field);
@@ -586,59 +483,45 @@ s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 stride,
return -EINVAL;
/* check if allocation would fit in scan area */
- if (w > INCL_LEN(end_x, start_x) || h > INCL_LEN(end_y, start_y))
+ if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
return -ENOSPC;
- start_x = ALIGN(start_x, stride);
+ start_x = ALIGN(start_x, align);
/* check if allocation would still fit in scan area */
- if (w > INCL_LEN(end_x, start_x))
+ 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;
- P2("ali=%d x=%d..%d y=%d..%d", stride, start_x, end_x, start_y, end_y);
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
- /*
- * Start scanning: These scans are always inclusive ones so if we are
- * given a start x = 0 is a valid value so if we have a end_x = 255,
- * 255th element is also checked
- */
- for (yy = start_y; yy <= end_y && !done; yy++) {
- for (xx = start_x; xx <= end_x; xx += stride) {
- /* if NOT occupied */
- if (!pvt->map[xx][yy]) {
- if (check_fit_r_and_b(tcm, w, h, xx, yy)) {
- P3("found shoulder: %d,%d", xx, yy);
- found_x = xx;
- found_y = yy;
- /* Insert this candidate, it is just a
- co-ordinate, reusing Area */
- done = update_candidate(tcm, xx, yy, w,
- h, field, CR_L2R_T2B, &best);
- if (done)
- break;
+ /* 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)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_L2R_T2B, &best))
+ goto done;
#ifdef X_SCAN_LIMITER
- /* change upper x bound */
- end_x = xx - 1;
+ /* change upper x bound */
+ end_x = x - 1;
#endif
- break;
- }
- } else {
- /* Optimization required only for Non Aligned,
- Aligned anyways skip by 32/64 tiles at a time */
- if (stride == 1 &&
- pvt->map[xx][yy]->is2d) {
- xx = pvt->map[xx][yy]->p1.x;
- P3("moving to: %d,%d", xx, yy);
- }
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN_DOWN(map[x][y]->p1.x, align);
+ P3("moving to: %d,%d", x, y);
}
}
- /* if you find a free area shouldering the given scan area on
- then we can break */
#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
if (found_x == start_x)
break;
#endif
@@ -646,33 +529,30 @@ s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 stride,
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;
}
#ifdef SCAN_BOTTOM_UP
/**
- * @description: raster scan left to right from bottom to top; find if there is
- * a free area to fit a given w x h inside the 'scan area'. If there is a free
- * area, then adds to maybes candidates, which later is sent for selection
- * as per pre-defined criteria.
- *
- * @input:'w x h' width and height of the allocation area.
- * 'stride' - 64/32/None for start address alignment
- * 'field' - area in which the scan operation should take place
+ * Raster scan horizontally left to right from bottom to top to find a
+ * place for a 2D area of given size inside a scan field.
*
- * @return 0 on success, non-0 error value on failure. On success
- * the 'area' area contains TL and BR corners of the allocated area
+ * @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_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
+static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 align,
struct tcm_area *field, struct tcm_area *area)
{
- s32 xx = 0, yy = 0, done = 0;
- s16 start_x = -1, end_x = -1, start_y = -1, end_y = -1;
- s16 found_x = -1, found_y = -1;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ 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};
PA(2, "scan_l2r_b2t:", field);
@@ -688,61 +568,46 @@ static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
return -EINVAL;
/* check if allocation would fit in scan area */
- if (w > INCL_LEN(end_x, start_x) || h > INCL_LEN(start_y, end_y))
+ if (w > LEN(end_x, start_x) || h > LEN(start_y, end_y))
return -ENOSPC;
- start_x = ALIGN(start_x, stride);
+ start_x = ALIGN(start_x, align);
/* check if allocation would still fit in scan area */
- if (w > INCL_LEN(end_x, start_x))
+ if (w > LEN(end_x, start_x))
return -ENOSPC;
/* adjust end_x and start_y, as allocation would not fit beyond */
end_x = end_x - w + 1; /* + 1 to be inclusive */
start_y = start_y - h + 1;
- P2("ali=%d x=%d..%d y=%d..%d", stride, start_x, end_x, start_y, end_y);
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
- /*
- * Start scanning: These scans are always inclusive ones so if we are
- * given a start x = 0 is a valid value so if we have a end_x = 255,
- * 255th element is also checked
- */
- for (yy = start_y; yy >= end_y && !done; yy--) {
- for (xx = start_x; xx <= end_x; xx += stride) {
- /* if NOT occupied */
- if (!pvt->map[xx][yy]) {
- if (check_fit_r_and_b(tcm, w, h, xx, yy)) {
- P3("found shoulder: %d,%d", xx, yy);
- found_x = xx;
- found_y = yy;
- /* Insert this candidate, it is just a
- co-ordinate, reusing Area */
- done = update_candidate(tcm, xx, yy, w,
- h, field, CR_L2R_B2T, &best));
- if (done)
- break;
+ /* scan field bottom-to-top, 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)) {
+ P3("found shoulder: %d,%d", x, y);
+ found_x = x;
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_L2R_B2T, &best))
+ goto done;
#ifdef X_SCAN_LIMITER
- /* change upper x bound */
- end_x = xx - 1;
+ /* change upper x bound */
+ end_x = x - 1;
#endif
- break;
- }
- } else {
- /* Optimization required only for Non Aligned,
- Aligned anyways skip by 32/64 tiles at a time */
- if (stride == 1 &&
- pvt->map[xx][yy]->is2d) {
- xx = pvt->map[xx][yy]->p1.x;
- P3("moving to: %d,%d", xx, yy);
- }
+ break;
+ } else if (map[x][y] && map[x][y]->is2d) {
+ /* step over 2D areas */
+ x = ALIGN_DOWN(map[x][y]->p1.x, align);
+ P3("moving to: %d,%d", x, y);
}
}
- /* if you find a free area shouldering the given scan area on
- then we can break */
#ifdef Y_SCAN_LIMITER
+ /* break if you find a free area shouldering the scan field */
if (found_x == start_x)
break;
#endif
@@ -750,39 +615,31 @@ static s32 scan_l2r_b2t(struct tcm *tcm, u16 w, u16 h, u16 stride,
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;
}
#endif
-/*
-Note: In General the cordinates specified in the scan area area relevant to the
-scan sweep directions. i.e A scan Area from Top Left Corner will have
-p0.x <= p1.x and p0.y <= p1.y. Where as A scan Area from bottom Right Corner
-will have p1.x <= p0.x and p1.y <= p0.y
-*/
/**
- * @description: raster scan right to left from bottom to top; find if there are
- * continuous free pages(one slot is one page, continuity always from left to
- * right) inside the 'scan area'. If there are enough continous free pages,
- * then it returns the start and end Tile/page co-ordinates inside 'area'
- *
- * @input:'num_pages' required,
- * 'field' - area in which the scan operation should take place
+ * 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.
*
- * @return 0 on success, non-0 error value on failure. On success
- * the 'area' area contains start and end slot (inclusive).
+ * @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_pages,
- struct tcm_area *field, struct tcm_area *area)
+static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_slots,
+ struct tcm_area *field, struct tcm_area *area)
{
- s32 fit = false;
- u16 x, y;
- u16 left_x, left_y, busy_x, busy_y;
- s32 ret = 0;
+ 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)
@@ -790,249 +647,171 @@ static s32 scan_r2l_b2t_one_dim(struct tcm *tcm, u32 num_pages,
PA(2, "scan_r2l_b2t_one_dim:", field);
- /* Note: Checking sanctity of scan area
- * The reason for checking this that 1D allocations assume that the X
- ranges the entire TilerSpace X ie ALL Columns
- * The scan area can limit only the Y ie, Num of Rows for 1D allocation.
- We also expect we could have only 1 row for 1D allocation
- * i.e our field p0.y and p1.y may have a same value.
+ /**
+ * Currently we only support full width 1D scan field, which makes sense
+ * since 1D slot-ordering spans the full container width.
*/
-
- /* only support full width 1d scan area */
- if (pvt->width != field->p0.x - field->p1.x + 1)
+ if (tcm->width != field->p0.x - field->p1.x + 1)
return -EINVAL;
/* check if allocation would fit in scan area */
- if (num_pages > pvt->width * INCL_LEN(field->p0.y, field->p1.y))
+ if (num_slots > tcm->width * LEN(field->p0.y, field->p1.y))
return -ENOSPC;
- left_x = field->p0.x;
- left_y = field->p0.y;
- while (!ret) {
- x = left_x;
- y = left_y;
-
- if (!pvt->map[x][y]) {
- ret = move_left(tcm, x, y, num_pages - 1,
- &left_x, &left_y);
- if (ret)
- break; /* out of space */
-
- P3("moved left %d slots: %d,%d", num_pages - 1,
- left_x, left_y);
- fit = check_fit_r_one_dim(tcm, left_x, left_y,
- num_pages, &busy_x, &busy_y);
- if (fit) {
- assign(area, left_x, left_y,
- busy_x, busy_y);
- break;
- } else {
- /* no fit, continue at the busy slot */
- x = busy_x;
- y = busy_y;
- }
+ 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;
}
- /* now the tile is occupied, skip busy region */
- if (pvt->map[x][y]->is2d) {
- busy_x = pvt->map[x][y]->p0.x;
- busy_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 {
- busy_x = pvt->map[x][y]->p0.x;
- busy_y = pvt->map[x][y]->p0.y;
+ /* count consecutive free slots */
+ found++;
}
- x = busy_x;
- y = busy_y;
- P3("moving left from: %d,%d", x, y);
- ret = move_left(tcm, x, y, 1, &left_x, &left_y);
+ /* move to the left */
+ if (x == 0)
+ y--;
+ x = (x ? : tcm->width) - 1;
+
}
- return fit ? 0 : -ENOSPC;
+ /* set top-left corner */
+ area->p0.x = x;
+ area->p0.y = y;
+ return 0;
}
/**
- * @description:
- *
+ * 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
*
- *
- * @input:
- *
- *
- * @return 0 on success, non-0 error value on failure. On success
+ * @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 stride,
- struct tcm_area *area)
+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 = 0, boundary_y = 0;
+ u16 boundary_x, boundary_y;
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- s32 need_scan = 2;
- if (stride > 1) {
+ if (align > 1) {
+ /* prefer top-left corner */
boundary_x = pvt->div_pt.x - 1;
boundary_y = pvt->div_pt.y - 1;
- /* more intelligence here */
- if (w > pvt->div_pt.x) {
- boundary_x = pvt->width - 1;
- need_scan--;
- }
- if (h > pvt->div_pt.y) {
- boundary_y = pvt->height - 1;
- need_scan--;
- }
+ /* 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, stride, &field, area);
- if (ret != 0 && need_scan) {
+ 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, pvt->width - 1, pvt->height - 1);
- ret = scan_l2r_t2b(tcm, w, h, stride, &field, area);
+ assign(&field, 0, 0, tcm->width - 1, tcm->height - 1);
+ ret = scan_l2r_t2b(tcm, w, h, align, &field, area);
}
- } else if (stride == 1) {
+ } else if (align == 1) {
+ /* prefer top-right corner */
boundary_x = pvt->div_pt.x;
boundary_y = pvt->div_pt.y - 1;
- /* more intelligence here */
- if (w > (pvt->width - pvt->div_pt.x)) {
+ /* expand width and height if needed */
+ if (w > (tcm->width - pvt->div_pt.x))
boundary_x = 0;
- need_scan--;
- }
- if (h > pvt->div_pt.y) {
- boundary_y = pvt->height - 1;
- need_scan--;
- }
+ if (h > pvt->div_pt.y)
+ boundary_y = tcm->height - 1;
- assign(&field, pvt->width - 1, 0, boundary_x, boundary_y);
- ret = scan_r2l_t2b(tcm, w, h, stride, &field, area);
+ assign(&field, tcm->width - 1, 0, boundary_x, boundary_y);
+ ret = scan_r2l_t2b(tcm, w, h, align, &field, area);
- if (ret != 0 && need_scan) {
+ /* 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, pvt->width - 1, 0, 0,
- pvt->height - 1);
- ret = scan_r2l_t2b(tcm, w, h, stride, &field,
+ assign(&field, tcm->width - 1, 0, 0, tcm->height - 1);
+ ret = scan_r2l_t2b(tcm, w, h, align, &field,
area);
}
}
- /* 3/30/2010: moved aligned to left, and unaligned to right side. */
-#if 0
- else if (stride == 1) {
- /* use 64-align area so we don't grow down and shrink 1D area */
- if (h > pvt->div_pt.y) {
- need_scan -= 2;
- assign(&field, 0, 0, pvt->width - 1, pvt->height - 1);
- ret = scan_l2r_t2b(tcm, w, h, stride, &field, area);
- } else {
- assign(&field, 0, pvt->div_pt.y - 1, pvt->width - 1, 0);
- /* scan up in 64 and 32 areas accross whole width */
- ret = scan_l2r_b2t(tcm, w, h, stride, &field, area);
- }
-
- if (ret != 0 && need_scan) {
- assign(&field, 0, 0, pvt->width - 1, pvt->height - 1);
- ret = scan_l2r_t2b(tcm, w, h, stride, &field, area);
- }
- }
-#endif
return ret;
}
-static s32 check_fit_r_and_b(struct tcm *tcm, u16 w, u16 h, u16 left_x,
- u16 top_y)
+/* 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 xx = 0, yy = 0;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
-
- for (yy = top_y; yy < top_y + h; yy++) {
- for (xx = left_x; xx < left_x + w; xx++) {
- if (pvt->map[xx][yy])
+ 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;
}
-static s32 check_fit_r_one_dim(struct tcm *tcm, u16 x, u16 y, u32 num_pages,
- u16 *busy_x, u16 *busy_y)
-{
- s32 ret = 0;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- s32 i = 0;
- *busy_x = x;
- *busy_y = y;
-
- P2("checking fit for %d pages from %d,%d", num_pages, x, y);
- while (i < num_pages) {
- if (pvt->map[x][y]) {
- /* go to the start of the blocking allocation
- to avoid unecessary checking */
- if (pvt->map[x][y]->is2d) {
- *busy_x = pvt->map[x][y]->p0.x;
- *busy_y = y;
- } else {
- *busy_x = pvt->map[x][y]->p0.x;
- *busy_y = pvt->map[x][y]->p0.y;
- }
- /* TODO: Could also move left in case of 2D */
- P2("after busy slot at: %d,%d", *busy_x, *busy_y);
- return false;
- }
-
- i++;
-
- /* break here so busy_x, busy_y will be correct */
- if (i == num_pages)
- break;
-
- ret = move_right(tcm, x, y, 1, busy_x, busy_y);
- if (ret)
- return false;
-
- x = *busy_x;
- y = *busy_y;
- }
-
- return true;
-}
-
-static void fill_2d_area(struct tcm *tcm, struct tcm_area *area,
+/* 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_;
- PA(2, "fill 2d area", area);
- for (x = area->p0.x; x <= area->p1.x; ++x)
- for (y = area->p0.y; y <= area->p1.y; ++y)
- pvt->map[x][y] = parent;
-}
-
-/* area should be a valid area */
-static void fill_1d_area(struct tcm *tcm, struct tcm_area *area,
- struct tcm_area *parent)
-{
- u16 x = 0, y = 0;
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ /* set area's tcm; otherwise, enumerator considers it invalid */
+ area->tcm = tcm;
- PA(2, "fill 1d area", area);
- x = area->p0.x;
- y = area->p0.y;
+ tcm_for_each_slice(a, *area, a_) {
+ PA(2, "fill 2d 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;
- while (!(x == area->p1.x && y == area->p1.y)) {
- pvt->map[x++][y] = parent;
- if (x == pvt->width) {
- x = 0;
- y++;
- }
}
- /* set the last slot */
- 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)
@@ -1041,9 +820,9 @@ static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
/*
* If first found is enabled then we stop looking
- * 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.
+ * 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_FIRST_FOUND | CR_BIAS_HORIZONTAL);
@@ -1051,8 +830,8 @@ static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
/* calculate score for current candidate */
if (!first) {
- get_busy_neigh_stats(tcm, w, h, &me.a, &me.n);
- me.neighs = BOUNDARY(&me.n) + OCCUPIED(&me.n);
+ get_neighbor_stats(tcm, &me.a, &me.n);
+ me.neighs = me.n.edge + me.n.busy;
get_nearness_factor(field, &me.a, &me.f);
}
@@ -1060,9 +839,7 @@ static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
if (!best->a.tcm)
goto better;
- /***** TEMP *****/
- if (first)
- return 0;
+ BUG_ON(first);
/* see if this are is better than the best so far */
@@ -1077,8 +854,8 @@ static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
* NOTE: not checking if lengths are same, because that does not
* find new shoulders on the same row after a fit
*/
- INCL_LEN_MOD(me.a.p0.y, field->p0.y) >
- INCL_LEN_MOD(best->a.p0.y, field->p0.y))
+ LEN(me.a.p0.y, field->p0.y) >
+ LEN(best->a.p0.y, field->p0.y))
goto better;
/* diagonal balance check */
@@ -1086,8 +863,8 @@ static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
best->neighs <= me.neighs &&
(best->neighs < me.neighs ||
/* this implies that neighs and occupied match */
- OCCUPIED(&best->n) < OCCUPIED(&me.n) ||
- (OCCUPIED(&best->n) == OCCUPIED(&me.n) &&
+ 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;
@@ -1102,130 +879,56 @@ better:
return first;
}
-/* get the nearness factor of an area in a search field */
-static void get_nearness_factor(struct tcm_area *field,
- struct tcm_area *area, struct nearness_factor *nf)
+/**
+ * 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)
{
- /* For the following calculation we need worry of +/- sign, the
- relative distances take of this. Multiplied by 1000, there
- is no floating point arithmetic used in kernel */
-
+ /**
+ * 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);
}
-/* Neighbours
- *
- * |<-----T------>|
- * _ _______________ _
- * L | Ar | R
- * _ |______________|_
- * |<-----B------>|
- */
-static s32 get_busy_neigh_stats(struct tcm *tcm, u16 width, u16 height,
- struct tcm_area *top_left_corner,
- struct neighbour_stats *neighbour_stat)
+/* get neighbor statistics */
+static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
+ struct neighbor_stats *stat)
{
- s16 xx = 0, yy = 0;
- struct tcm_area left_edge;
- struct tcm_area right_edge;
- struct tcm_area top_edge;
- struct tcm_area bottom_edge;
+ s16 x = 0, y = 0;
struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- if (neighbour_stat == NULL)
- return -EINVAL;
-
- if (width == 0 || height == 0)
- return -EINVAL;
-
/* Clearing any exisiting values */
- memset(neighbour_stat, 0, sizeof(*neighbour_stat));
-
- /* Finding Top Edge */
- assign(&top_edge, top_left_corner->p0.x, top_left_corner->p0.y,
- top_left_corner->p0.x + width - 1, top_left_corner->p0.y);
-
- /* Finding Bottom Edge */
- assign(&bottom_edge, top_left_corner->p0.x,
- top_left_corner->p0.y+height - 1,
- top_left_corner->p0.x + width - 1,
- top_left_corner->p0.y + height - 1);
-
- /* Finding Left Edge */
- assign(&left_edge, top_left_corner->p0.x, top_left_corner->p0.y,
- top_left_corner->p0.x, top_left_corner->p0.y + height - 1);
-
- /* Finding Right Edge */
- assign(&right_edge, top_left_corner->p0.x + width - 1,
- top_left_corner->p0.y,
- top_left_corner->p0.x + width - 1,
- top_left_corner->p0.y + height - 1);
-
- /* dump_area(&top_edge);
- dump_area(&right_edge);
- dump_area(&bottom_edge);
- dump_area(&left_edge);
- */
-
- /* Parsing through top & bottom edge */
- for (xx = top_edge.p0.x; xx <= top_edge.p1.x; xx++) {
- if (top_edge.p0.y - 1 < 0)
- neighbour_stat->top_boundary++;
- else if (pvt->map[xx][top_edge.p0.y - 1])
- neighbour_stat->top_occupied++;
-
- if (bottom_edge.p0.y + 1 > pvt->height - 1)
- neighbour_stat->bottom_boundary++;
- else if (pvt->map[xx][bottom_edge.p0.y+1])
- neighbour_stat->bottom_occupied++;
+ 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++;
}
- /* Parsing throught left and right edge */
- for (yy = left_edge.p0.y; yy <= left_edge.p1.y; ++yy) {
- if (left_edge.p0.x - 1 < 0)
- neighbour_stat->left_boundary++;
- else if (pvt->map[left_edge.p0.x - 1][yy])
- neighbour_stat->left_occupied++;
-
- if (right_edge.p0.x + 1 > pvt->width - 1)
- neighbour_stat->right_boundary++;
- else if (pvt->map[right_edge.p0.x + 1][yy])
- neighbour_stat->right_occupied++;
-
+ /* 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++;
}
-
- return 0;
-}
-
-static s32 move_left(struct tcm *tcm, u16 x, u16 y, u32 num_pages,
- u16 *xx, u16 *yy)
-{
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- u32 pos = x + pvt->width * y;
-
- if (pos < num_pages)
- return -ENOSPC;
-
- pos -= num_pages;
- *xx = pos % pvt->width;
- *yy = pos / pvt->width;
- return 0;
-}
-
-static s32 move_right(struct tcm *tcm, u16 x, u16 y, u32 num_pages,
- u16 *xx, u16 *yy)
-{
- struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
- u32 pos = x + pvt->width * y;
-
- if (num_pages > pvt->width * pvt->height - pos)
- return -ENOSPC;
-
- pos += num_pages;
- *xx = pos % pvt->width;
- *yy = pos / pvt->width;
- return 0;
}
diff --git a/drivers/media/video/tiler/tcm/tcm-sita.h b/drivers/media/video/tiler/tcm/tcm-sita.h
index 8b6607652bb..6098ea00fb2 100644
--- a/drivers/media/video/tiler/tcm/tcm-sita.h
+++ b/drivers/media/video/tiler/tcm/tcm-sita.h
@@ -16,8 +16,8 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#ifndef TCM_SITA_H_
-#define TCM_SITA_H_
+#ifndef TCM_SITA_H
+#define TCM_SITA_H
#include "../tcm.h"