From aa56c7eddfafeed7246193036903f6f4ba827767 Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Thu, 12 Jan 2012 19:08:36 +0100 Subject: OMAP4: TILER: Add offset parameter for allocation Add offset parameter for use in tiler_alloc_block_area_aligned. This allows a user to get a tiler allocation with a specific alignment and offset. Change-Id: I8b1b9dd17bc9def124ea92cbbede2f3c56823387 Signed-off-by: Andy Gross Signed-off-by: Tony Zlatinski Signed-off-by: Atanas (Tony) Zlatinski --- drivers/media/video/tiler/_tiler.h | 7 +-- drivers/media/video/tiler/tiler-iface.c | 2 +- drivers/media/video/tiler/tiler-ioctl.c | 2 + drivers/media/video/tiler/tiler-main.c | 89 +++++++++++++++++++------------ drivers/media/video/tiler/tiler-nv12.c | 8 +-- drivers/media/video/tiler/tiler-reserve.c | 9 ++-- 6 files changed, 70 insertions(+), 47 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/tiler/_tiler.h b/drivers/media/video/tiler/_tiler.h index 784e66b8f4e..382239de316 100644 --- a/drivers/media/video/tiler/_tiler.h +++ b/drivers/media/video/tiler/_tiler.h @@ -126,7 +126,7 @@ struct tiler_ops { void (*reserve_nv12) (u32 n, u32 width, u32 height, u32 gid, struct security_info *si); void (*reserve) (u32 n, enum tiler_fmt fmt, u32 width, u32 height, - u32 gid, struct security_info *si); + u32 align, u32 offs, u32 gid, struct security_info *si); void (*unreserve) (u32 gid, struct security_info *si); /* block access operations */ @@ -136,7 +136,7 @@ struct tiler_ops { void (*unlock_free) (struct mem_info *mi, bool free); s32 (*lay_2d) (enum tiler_fmt fmt, u16 n, u16 w, u16 h, u16 band, - u16 align, struct gid_info *gi, + u16 align, u16 offs, struct gid_info *gi, struct list_head *pos); #ifdef CONFIG_TILER_ENABLE_NV12 s32 (*lay_nv12) (int n, u16 w, u16 w1, u16 h, struct gid_info *gi, @@ -153,7 +153,8 @@ struct tiler_ops { /* area operations */ s32 (*analize) (enum tiler_fmt fmt, u32 width, u32 height, - u16 *x_area, u16 *y_area, u16 *band, u16 *align); + u16 *x_area, u16 *y_area, u16 *band, u16 *align, + u16 *offs, u16 *remainder); /* process operations */ void (*cleanup) (void); diff --git a/drivers/media/video/tiler/tiler-iface.c b/drivers/media/video/tiler/tiler-iface.c index 8d81f918bcd..3d5917f3fec 100644 --- a/drivers/media/video/tiler/tiler-iface.c +++ b/drivers/media/video/tiler/tiler-iface.c @@ -175,7 +175,7 @@ void tiler_reservex(u32 n, enum tiler_fmt fmt, u32 width, u32 height, struct security_info *si = __get_si(pid, true, SECURE_BY_PID); if (si) - ops->reserve(n, fmt, width, height, gid, si); + ops->reserve(n, fmt, width, height, PAGE_SIZE, 0, gid, si); } EXPORT_SYMBOL(tiler_reservex); diff --git a/drivers/media/video/tiler/tiler-ioctl.c b/drivers/media/video/tiler/tiler-ioctl.c index c39dd0fe946..99f8ad4afc6 100644 --- a/drivers/media/video/tiler/tiler-ioctl.c +++ b/drivers/media/video/tiler/tiler-ioctl.c @@ -422,6 +422,8 @@ static long tiler_ioctl(struct file *filp, u32 cmd, unsigned long arg) block_info.fmt, block_info.dim.area.width, block_info.dim.area.height, + PAGE_SIZE, + 0, block_info.group_id, si); break; /* unreserve blocks */ diff --git a/drivers/media/video/tiler/tiler-main.c b/drivers/media/video/tiler/tiler-main.c index 0c281663b52..f7887d4a561 100644 --- a/drivers/media/video/tiler/tiler-main.c +++ b/drivers/media/video/tiler/tiler-main.c @@ -457,10 +457,11 @@ static inline void _m_area_free(struct area_info *ai) } static s32 __analize_area(enum tiler_fmt fmt, u32 width, u32 height, - u16 *x_area, u16 *y_area, u16 *band, u16 *align) + u16 *x_area, u16 *y_area, u16 *band, u16 *align, + u16 *offs, u16 *remainder) { - /* input: width, height is in pixels, align */ - /* output: x_area, y_area, band */ + /* input: width, height is in pixels, align, offs in bytes */ + /* output: x_area, y_area, band, offs in slots, remaining bytes */ /* slot width, height, and row size */ u32 slot_row, min_align; @@ -477,9 +478,11 @@ static s32 __analize_area(enum tiler_fmt fmt, u32 width, u32 height, if (fmt == TILFMT_PAGE) { /* adjust size to accomodate offset, only do page alignment */ *align = PAGE_SIZE; + *remainder = *offs & ~PAGE_MASK; /* calculate remainder */ + width += *remainder; /* for 1D area keep the height (1), width is in tiler slots */ - *x_area = DIV_ROUND_UP(width, tiler.page); + *x_area = DIV_ROUND_UP(width , tiler.page); *y_area = *band = 1; if (*x_area * *y_area > tiler.width * tiler.height) @@ -487,6 +490,8 @@ static s32 __analize_area(enum tiler_fmt fmt, u32 width, u32 height, return 0; } + *remainder = 0; + /* format must be valid */ g = tiler.geom(fmt); if (!g) @@ -500,15 +505,26 @@ static s32 __analize_area(enum tiler_fmt fmt, u32 width, u32 height, /* minimum alignment is at least 1 slot */ min_align = max(slot_row, granularity); - - /* set alignment to page size by default and enforce minumum cache - line size */ *align = ALIGN(*align ? : PAGE_SIZE, min_align); + /* offset must be multiple of bpp */ + if (*offs & (g->bpp - 1) || *offs >= *align) + return -EINVAL; + + /* round down the offset to the nearest slot size, and increase width + to allow space for having the correct offset */ + width += (*offs & (min_align - 1)) / g->bpp; + + *offs &= ~(min_align - 1); + + /* expand width to block size */ + width = ALIGN(width, min_align / g->bpp); + /* adjust to slots */ *x_area = DIV_ROUND_UP(width, g->slot_w); *y_area = DIV_ROUND_UP(height, g->slot_h); *align /= slot_row; + *offs /= slot_row; if (*x_area > tiler.width || *y_area > tiler.height) return -ENOMEM; @@ -564,10 +580,10 @@ void fill_virt_array(struct tiler_block_t *blk, u32 *virt_array) * * (must have mutex) */ -static u16 _m_blk_find_fit(u16 w, u16 align, +static u16 _m_blk_find_fit(u16 w, u16 align, u16 offs, struct area_info *ai, struct list_head **before) { - int x = ai->area.p0.x + w; + int x = ai->area.p0.x + w + offs; struct mem_info *mi; /* area blocks are sorted by x */ @@ -577,7 +593,7 @@ static u16 _m_blk_find_fit(u16 w, u16 align, *before = &mi->by_area; return x; } - x = ALIGN(mi->area.p1.x + 1, align) + w; + x = ALIGN(mi->area.p1.x + 1 -offs, align) + w + offs; } *before = &ai->blocks; @@ -599,7 +615,7 @@ struct mem_info *_m_add2area(struct mem_info *mi, struct area_info *ai, return mi; } -static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 band, +static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 offs, u16 band, struct gid_info *gi, struct tcm *tcm) { struct area_info *ai = NULL; @@ -615,7 +631,7 @@ static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 band, if (mi->area.tcm == tcm && tcm_aheight(mi->area) == h && tcm_awidth(mi->area) == w && - (mi->area.p0.x & (align - 1)) == 0) { + (mi->area.p0.x & (align - 1)) == offs) { /* this area is already set up */ /* remove from reserved list */ @@ -646,7 +662,7 @@ static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 band, list_for_each_entry(ai, &gi->areas, by_gid) { if (ai->area.tcm == tcm && tcm_aheight(ai->area) == h) { - x = _m_blk_find_fit(w, align, ai, &before); + x = _m_blk_find_fit(w, align, offs, ai, &before); if (x) { _m_add2area(mi, ai, x - w, w, before); @@ -666,10 +682,10 @@ static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, u16 band, mutex_unlock(&mtx); /* if no area fit, reserve a new one */ - ai = area_new_m(ALIGN(w, max(band, align)), h, + ai = area_new_m(ALIGN(w + offs, max(band, align)), h, max(band, align), tcm, gi); if (ai) { - _m_add2area(mi, ai, ai->area.p0.x, w, &ai->blocks); + _m_add2area(mi, ai, ai->area.p0.x + offs, w, &ai->blocks); if (tiler_alloc_debug & 1) printk(KERN_ERR "(+2d (%d-%d,%d-%d) in (%d-%d,%d-%d) new)\n", mi->area.p0.x, mi->area.p1.x, @@ -688,9 +704,9 @@ done: } /* layout reserved 2d blocks in a larger area */ -/* NOTE: band, w, h, a(lign) is in slots */ +/* NOTE: band, w, h, a(lign), o(ffs) is in slots */ static s32 lay_2d(enum tiler_fmt fmt, u16 n, u16 w, u16 h, u16 band, - u16 align, struct gid_info *gi, + u16 align, u16 offs, struct gid_info *gi, struct list_head *pos) { u16 x, x0, e = ALIGN(w, align), w_res = (n - 1) * e + w; @@ -700,15 +716,15 @@ static s32 lay_2d(enum tiler_fmt fmt, u16 n, u16 w, u16 h, u16 band, printk(KERN_INFO "packing %u %u buffers into %u width\n", n, w, w_res); - /* calculate dimensions, band, and alignment in slots */ + /* calculate dimensions, band, offs, and alignment in slots */ /* reserve an area */ - ai = area_new_m(ALIGN(w_res, max(band, align)), h, + ai = area_new_m(ALIGN(w_res + offs, max(band, align)), h, max(band, align), tcm[fmt], gi); if (!ai) return -ENOMEM; /* lay out blocks in the reserved area */ - for (n = 0, x = 0; x < w_res; x += e, n++) { + for (n = 0, x = offs; x < w_res; x += e, n++) { /* reserve a block struct */ mi = kmalloc(sizeof(*mi), GFP_KERNEL); if (!mi) @@ -1095,14 +1111,15 @@ static void fill_block_info(struct mem_info *i, struct tiler_block_info *blk) * ========================================================================== */ static struct mem_info *alloc_area(enum tiler_fmt fmt, u32 width, u32 height, - struct gid_info *gi, u16 align) + struct gid_info *gi, u16 align, u16 offs) { - u16 x, y, band; + u16 x, y, band, remainder = 0; struct mem_info *mi = NULL; const struct tiler_geom *g = tiler.geom(fmt); /* calculate dimensions, band, and alignment in slots */ - if (__analize_area(fmt, width, height, &x, &y, &band, &align)) + if (__analize_area(fmt, width, height, &x, &y, &band, &align, &offs, + &remainder)) return NULL; if (fmt == TILFMT_PAGE) { @@ -1126,7 +1143,7 @@ static struct mem_info *alloc_area(enum tiler_fmt fmt, u32 width, u32 height, mi->parent = gi; list_add(&mi->by_area, &gi->onedim); } else { - mi = get_2d_area(x, y, align, band, gi, tcm[fmt]); + mi = get_2d_area(x, y, align, offs, band, gi, tcm[fmt]); if (!mi) return NULL; @@ -1140,19 +1157,20 @@ static struct mem_info *alloc_area(enum tiler_fmt fmt, u32 width, u32 height, mutex_unlock(&mtx); mi->blk.phys = tiler.addr(fmt, - mi->area.p0.x * g->slot_w, mi->area.p0.y * g->slot_h); + mi->area.p0.x * g->slot_w, + mi->area.p0.y * g->slot_h) + remainder; return mi; } static struct mem_info *alloc_block_area(enum tiler_fmt fmt, u32 width, u32 height, u32 key, u32 gid, - struct security_info *si, u16 align) + struct security_info *si, u16 align, u16 offs) { struct mem_info *mi = NULL; struct gid_info *gi = NULL; /* validate parameters */ - if (!si) + if (!si || align > PAGE_SIZE || offs >= (align ? : PAGE_SIZE)) return ERR_PTR(-EINVAL); /* get group context */ @@ -1164,7 +1182,7 @@ static struct mem_info *alloc_block_area(enum tiler_fmt fmt, u32 width, return ERR_PTR(-ENOMEM); /* reserve area in tiler container */ - mi = alloc_area(fmt, width, height, gi, align); + mi = alloc_area(fmt, width, height, gi, align, offs); if (!mi) { mutex_lock(&mtx); gi->refs--; @@ -1255,7 +1273,7 @@ static s32 alloc_block(enum tiler_fmt fmt, u32 width, u32 height, *info = NULL; /* allocate tiler container area */ - mi = alloc_block_area(fmt, width, height, key, gid, si, PAGE_SIZE); + mi = alloc_block_area(fmt, width, height, key, gid, si, PAGE_SIZE, 0); if (IS_ERR_OR_NULL(mi)) return mi ? -ENOMEM : PTR_ERR(mi); @@ -1398,7 +1416,7 @@ static s32 pin_any_block(enum tiler_fmt fmt, u32 width, u32 height, goto done; /* get allocation area */ - mi = alloc_block_area(fmt, width, height, key, gid, si, PAGE_SIZE); + mi = alloc_block_area(fmt, width, height, key, gid, si, PAGE_SIZE, 0); if (IS_ERR_OR_NULL(mi)) { res = mi ? PTR_ERR(mi) : -ENOMEM; goto done; @@ -1736,7 +1754,7 @@ tiler_blk_handle tiler_alloc_block_area(enum tiler_fmt fmt, u32 width, return NULL; mi = alloc_block_area(fmt, width, height, 0, 0, - __get_si(0, true, SECURE_BY_PID), PAGE_SIZE); + __get_si(0, true, SECURE_BY_PID), PAGE_SIZE, 0); if (IS_ERR_OR_NULL(mi)) goto done; @@ -1751,7 +1769,7 @@ EXPORT_SYMBOL(tiler_alloc_block_area); tiler_blk_handle tiler_alloc_block_area_aligned(enum tiler_fmt fmt, u32 width, u32 height, u32 *ssptr, u32 *virt_array, u32 align, - u32 token) + u32 offset, u32 token) { struct mem_info *mi; *ssptr = 0; @@ -1761,7 +1779,7 @@ tiler_blk_handle tiler_alloc_block_area_aligned(enum tiler_fmt fmt, u32 width, return NULL; mi = alloc_block_area(fmt, width, height, 0, 0, __get_si(token, true, - SECURE_BY_TOKEN), align); + SECURE_BY_TOKEN), align, offset); if (IS_ERR_OR_NULL(mi)) goto done; @@ -1785,13 +1803,14 @@ EXPORT_SYMBOL(tiler_unpin_block); s32 tiler_memsize(enum tiler_fmt fmt, u32 width, u32 height, u32 *alloc_pages, u32 *virt_pages) { - u16 x, y, band, align = PAGE_SIZE; + u16 x, y, band, align = PAGE_SIZE, offs = 0, remainder = 0; int res; struct tiler_block_t blk; *alloc_pages = *virt_pages = 0; - res = tiler.analize(fmt, width, height, &x, &y, &band, &align); + res = tiler.analize(fmt, width, height, &x, &y, &band, &align, &offs, + &remainder); if (!res) { blk.height = height; diff --git a/drivers/media/video/tiler/tiler-nv12.c b/drivers/media/video/tiler/tiler-nv12.c index f208275eb78..2142b3acc82 100644 --- a/drivers/media/video/tiler/tiler-nv12.c +++ b/drivers/media/video/tiler/tiler-nv12.c @@ -336,7 +336,7 @@ static u16 nv12_together(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *packing) static void reserve_nv12(u32 n, u32 width, u32 height, u32 gid, struct security_info *si) { - u16 w, h, band, a, o = 0; + u16 w, h, band, a, o = 0, r = 0; struct gid_info *gi; int res = 0, res2, i; u16 n_t, n_s, area_t, area_s; @@ -349,7 +349,7 @@ static void reserve_nv12(u32 n, u32 width, u32 height, return; /* calculate dimensions, band, and alignment in slots */ - if (ops->analize(TILFMT_8BIT, width, height, &w, &h, &band, &a)) + if (ops->analize(TILFMT_8BIT, width, height, &w, &h, &band, &a, &o, &r)) return; /* get group context */ @@ -378,10 +378,10 @@ static void reserve_nv12(u32 n, u32 width, u32 height, * able to reserve both 8- and 16-bit blocks as the * offsets of them must match. */ - res = ops->lay_2d(TILFMT_8BIT, n_s, w, h, band_8, a, + res = ops->lay_2d(TILFMT_8BIT, n_s, w, h, band_8, a, o, gi, &reserved); res2 = ops->lay_2d(TILFMT_16BIT, n_s, (w + 1) >> 1, h, - band_16, a >> 1, gi, &reserved); + band_16, a >> 1, o >> 1, gi, &reserved); if (res2 < 0 || res < 0 || res != res2) { /* clean up */ diff --git a/drivers/media/video/tiler/tiler-reserve.c b/drivers/media/video/tiler/tiler-reserve.c index c5a4f9c3b0e..198636325a9 100644 --- a/drivers/media/video/tiler/tiler-reserve.c +++ b/drivers/media/video/tiler/tiler-reserve.c @@ -77,16 +77,17 @@ u32 tiler_best2pack(u16 o, u16 a, u16 b, u16 w, u16 *n, u16 *_area) /* reserve 2d blocks */ static void reserve_blocks(u32 n, enum tiler_fmt fmt, u32 width, u32 height, - u32 gid, + u32 align, u32 offs, u32 gid, struct security_info *si) { u32 bpt, res = 0, i; - u16 a, band, w, h, n_try; + u16 o = offs, a = align, r = 0, band, w, h, n_try; struct gid_info *gi; const struct tiler_geom *g; /* Check input parameters for correctness, and support */ if (!width || !height || !n || + align > PAGE_SIZE || offs >= align || fmt < TILFMT_8BIT || fmt > TILFMT_32BIT) return; @@ -99,7 +100,7 @@ static void reserve_blocks(u32 n, enum tiler_fmt fmt, u32 width, u32 height, * sufficient. Also check for basic area info. */ if (width * g->bpp * 2 <= PAGE_SIZE || - ops->analize(fmt, width, height, &w, &h, &band, &a)) + ops->analize(fmt, width, height, &w, &h, &band, &a, &o, &r)) return; /* get group id */ @@ -116,7 +117,7 @@ static void reserve_blocks(u32 n, enum tiler_fmt fmt, u32 width, u32 height, res = -1; while (n_try > 1) { /* adjust res so we fail on 0 return value */ - res = ops->lay_2d(fmt, n_try, w, h, band, a, + res = ops->lay_2d(fmt, n_try, w, h, band, a, o, gi, &gi->reserved) - 1; if (res >= 0) break; -- cgit v1.2.3