/* * memmgr.c * * Memory Allocator Interface functions for TI OMAP processors. * * Copyright (C) 2009-2011 Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #define BUF_ALLOCED 1 #define BUF_MAPPED 2 #define BUF_ANY ~0 #include typedef struct tiler_block_info tiler_block_info; #define __DEBUG__ #undef __DEBUG_ENTRY__ #define __DEBUG_ASSERT__ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "utils.h" #include "list_utils.h" #include "debug_utils.h" #include "tilermem.h" #include "tilermem_utils.h" #include "memmgr.h" /* list of allocations */ struct _AllocData { struct tiler_buf_info buf; int buf_type; struct _AllocList { struct _AllocList *next, *last; struct _AllocData *me; } link; }; static struct _AllocList bufs = {0}; static int bufs_inited = 0; typedef struct _AllocList _AllocList; typedef struct _AllocData _AllocData; static int refCnt = 0; static int td = -1; static pthread_mutex_t ref_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t che_mutex = PTHREAD_MUTEX_INITIALIZER; /** * Initializes the static structures * * @author a0194118 (9/8/2009) */ static void init() { if (!bufs_inited) { DLIST_INIT(bufs); bufs_inited = 1; } } /** * Increases the reference count. Initialized tiler if this was * the first reference * * @author a0194118 (9/2/2009) * * @return 0 on success, non-0 error value on failure. */ static int inc_ref() { /* initialize tiler on first call */ pthread_mutex_lock(&ref_mutex); int res = MEMMGR_ERR_NONE; if (!refCnt++) { /* initialize lists */ init(); #ifndef STUB_TILER td = open("/dev/tiler", O_RDWR | O_SYNC); if (NOT_I(td,>=,0)) res = MEMMGR_ERR_GENERIC; #else td = 2; res = MEMMGR_ERR_NONE; #endif } if (res) { refCnt--; } pthread_mutex_unlock(&ref_mutex); return res; } /** * Decreases the reference count. Deinitialized tiler if this * was the last reference * * @author a0194118 (9/2/2009) * * @return 0 on success, non-0 error value on failure. */ static int dec_ref() { pthread_mutex_lock(&ref_mutex); int res = MEMMGR_ERR_NONE;; if (refCnt <= 0) res = MEMMGR_ERR_GENERIC; else if (!--refCnt) { #ifndef STUB_TILER close(td); td = -1; #endif } pthread_mutex_unlock(&ref_mutex); return res; } /** * Returns the default page stride for this block * * @author a0194118 (9/4/2009) * * @param width Width of 2D container in bytes * * @return Stride */ static bytes_t def_stride(bytes_t width) { return ROUND_UP_TO2POW(width, PAGE_SIZE); } /** * Returns the bytes per pixel for the pixel format. * * @author a0194118 (9/4/2009) * * @param pixelFormat Pixelformat * * @return Bytes per pixel */ static bytes_t def_bpp(pixel_fmt_t pixelFormat) { return (pixelFormat == PIXEL_FMT_32BIT ? 4 : pixelFormat == PIXEL_FMT_16BIT ? 2 : 1); } /** * Returns the size of the supplied block * * @author a0194118 (9/4/2009) * * @param blk Pointer to the tiler_block_info struct * * @return size of the block in bytes */ static bytes_t def_size(tiler_block_info *blk) { return (blk->fmt == PIXEL_FMT_PAGE ? def_stride(blk->dim.len) : blk->dim.area.height * def_stride(blk->dim.area.width * def_bpp(blk->fmt))); } /** * Returns the map size based on an offset and buffer size * * @author a0194118 (7/8/2010) * * @param size Size of buffer * @param offs Buffer offset * * @return (page aligned) size for mapping */ static bytes_t map_size(bytes_t size, bytes_t offs) { return def_stride(size + (offs & (PAGE_SIZE - 1))); } /** * Records a buffer-pointer -- tiler-ID mapping for a specific * buffer type. * * @author a0194118 (9/7/2009) * * @param bufPtr Buffer pointer * @param tiler_id Tiler ID * @param buf_type Buffer type: BUF_ALLOCED or BUF_MAPPED * * @return 0 on success, -ENOMEM on memory allocation failure */ static int buf_cache_add(struct tiler_buf_info *buf, int buf_type) { pthread_mutex_lock(&che_mutex); _AllocData *ad = NEW(_AllocData); if (ad) { memcpy(&ad->buf, buf, sizeof(ad->buf)); ad->buf_type = buf_type; DLIST_MADD_BEFORE(bufs, ad, link); } pthread_mutex_unlock(&che_mutex); return ad == NULL ? -ENOMEM : 0; } /** * Retrieves the tiler ID for given pointer and buffer type from * the records. If the pointer lies within a tracked buffer, * the tiler ID is returned. Otherwise 0 is returned. * * @author a0194118 (9/7/2009) * * @param bufPtr Buffer pointer * @param buf_type Buffer type: BUF_ALLOCED or BUF_MAPPED * * @return Tiler ID on success, 0 on failure. */ static void buf_cache_query(void *ptr, struct tiler_buf_info *buf, int buf_type_mask) { IN; if(0) DP("in(p=%p,t=%d,bp*=%p)", ptr, buf_type_mask, buf->blocks[0].ptr); _AllocData *ad; pthread_mutex_lock(&che_mutex); DLIST_MLOOP(bufs, ad, link) { if(0) { DP("got(%p-%p,%d)", ad->buf.blocks->ptr, ad->buf.blocks->ptr + ad->buf.length, ad->buf_type); CHK_P(ad->buf.blocks->ptr,<=,ptr); CHK_P(ptr,<,ad->buf.blocks->ptr + ad->buf.length); CHK_I(ad->buf_type & buf_type_mask,!=,0); CHK_P(buf->blocks->ptr,!=,0); } if ((ad->buf_type & buf_type_mask) && ad->buf.blocks->ptr <= ptr && ptr < ad->buf.blocks->ptr + ad->buf.length) { memcpy(buf, &ad->buf, sizeof(*buf)); pthread_mutex_unlock(&che_mutex); return; } } pthread_mutex_unlock(&che_mutex); ZERO(*buf); OUT; } /** * Retrieves the tiler ID for given buffer pointer and buffer * type from the records. If the tiler ID is found, it is * removed from the records as well. * * @author a0194118 (9/7/2009) * * @param bufPtr Buffer pointer * @param buf_type Buffer type: BUF_ALLOCED or BUF_MAPPED * * @return Tiler ID on success, 0 on failure. */ static void buf_cache_del(void *bufPtr, struct tiler_buf_info *buf, int buf_type) { _AllocData *ad; pthread_mutex_lock(&che_mutex); DLIST_MLOOP(bufs, ad, link) { if (ad->buf.blocks->ptr == bufPtr && ad->buf_type == buf_type) { memcpy(buf, &ad->buf, sizeof(*buf)); DLIST_REMOVE(ad->link); FREE(ad); pthread_mutex_unlock(&che_mutex); return; } } pthread_mutex_unlock(&che_mutex); OUT; return; } /** * Checks the consistency of the internal record cache. The * number of elements in the cache should equal to the number of * references. * * @author a0194118 (9/7/2009) * * @return 0 on success, non-0 error value on failure. */ static int cache_check() { int num_bufs = 0; pthread_mutex_lock(&che_mutex); init(); _AllocData *ad; DLIST_MLOOP(bufs, ad, link) { num_bufs++; } pthread_mutex_unlock(&che_mutex); return (num_bufs == refCnt) ? MEMMGR_ERR_NONE : MEMMGR_ERR_GENERIC; } static void dump_block(struct tiler_block_info *blk, char *prefix, char *suffix) { #if 0 switch (blk->fmt) { case TILFMT_PAGE: P("%s [%d:(%d,%08x), p=%p(0x%x),l=0x%x,s=%d,%d+%d]%s", prefix, blk->group_id, blk->key, blk->id, blk->ptr, blk->ssptr, blk->dim.len, blk->stride, blk->align, blk->offs, suffix); break; case TILFMT_8BIT: case TILFMT_16BIT: case TILFMT_32BIT: P("%s [%d:(%d,%08x), p=%p(0x%x),%d*%d*%d,s=%d,%d+%d]%s", prefix, blk->group_id, blk->key, blk->id, blk->ptr, blk->ssptr, blk->dim.area.width, blk->dim.area.height, def_bpp(blk->fmt) * 8, blk->stride, blk->align, blk->offs, suffix); break; default: P("%s*[%d:(%d,%08x), p=%p(0x%x),l=0x%x,s=%d,%d+%d,fmt=0x%x]%s", prefix, blk->group_id, blk->key, blk->id, blk->ptr, blk->ssptr, blk->dim.len, blk->stride, blk->align, blk->offs, blk->fmt, suffix); } #endif } static void dump_buf(struct tiler_buf_info* buf, char* prefix) { #if 0 P("%sbuf={n=%d,id=0x%x,len=0x%x", prefix, buf->num_blocks, buf->offset, buf->length); int ix = 0; for (ix = 0; ix < buf->num_blocks; ix++) { dump_block(buf->blocks + ix, "", ix + 1 == buf->num_blocks ? "}" : ""); } #endif } /** * Returns the tiler format for an address * * @author a0194118 (9/7/2009) * * @param ssptr Address * * @return The tiler format */ static enum tiler_fmt tiler_get_fmt(SSPtr ssptr) { #ifndef STUB_TILER return (ssptr == 0 ? TILFMT_INVALID : ssptr < TILER_MEM_8BIT ? TILFMT_NONE : ssptr < TILER_MEM_16BIT ? TILFMT_8BIT : ssptr < TILER_MEM_32BIT ? TILFMT_16BIT : ssptr < TILER_MEM_PAGED ? TILFMT_32BIT : ssptr < TILER_MEM_END ? TILFMT_PAGE : TILFMT_NONE); #else /* if emulating, we need to get through all allocated memory segments */ pthread_mutex_lock(&che_mutex); init(); _AllocData *ad; void *ptr = (void *) ssptr; if (!ptr) return TILFMT_INVALID; /* P("?%p", (void *)ssptr); */ DLIST_MLOOP(bufs, ad, link) { int ix; struct tiler_buf_info *buf = (struct tiler_buf_info *) ad->buf.offset; /* P("buf[%d]", buf->num_blocks); */ for (ix = 0; ix < buf->num_blocks; ix++) { /* P("block[%p-%p]", buf->blocks[ix].ptr, buf->blocks[ix].ptr + def_size(buf->blocks + ix)); */ if (ptr >= buf->blocks[ix].ptr && ptr < buf->blocks[ix].ptr + def_size(buf->blocks + ix)) { enum tiler_fmt fmt = buf->blocks[ix].fmt; pthread_mutex_unlock(&che_mutex); return fmt; } } } pthread_mutex_unlock(&che_mutex); return TILFMT_NONE; #endif } /** * Allocates a memory block using tiler * * @author a0194118 (9/7/2009) * * @param blk Pointer to the block info * * @return ssptr of block allocated, or 0 on error */ static int tiler_alloc(struct tiler_block_info *blk) { dump_block(blk, "=(ta)=>", ""); blk->ptr = NULL; int ret = A_S(ioctl(td, TILIOC_GBLK, blk),==,0); dump_block(blk, "alloced: ", ""); return R_I(ret); } /** * Frees a memory block using tiler * * @author a0194118 (9/7/2009) * * @param blk Pointer to the block info * * @return 0 on success, non-0 error value on failure. */ static int tiler_free(struct tiler_block_info *blk) { return R_I(ioctl(td, TILIOC_FBLK, blk)); } /** * Maps a memory block into tiler using tiler * * @author a0194118 (9/7/2009) * * @param blk Pointer to the block info * * @return ssptr of block mapped, or 0 on error */ static int tiler_map(struct tiler_block_info *blk) { dump_block(blk, "=(tm)=>", ""); int ret = A_S(ioctl(td, TILIOC_MBLK, blk),==,0); dump_block(blk, "mapped: ", ""); return R_I(ret); } /** * Unmaps a memory block from tiler using tiler * * @author a0194118 (9/7/2009) * * @param blk Pointer to the block info * * @return 0 on success, non-0 error value on failure. */ static int tiler_unmap(struct tiler_block_info *blk) { return ioctl(td, TILIOC_UMBLK, blk); } /** * Registers a buffer structure with tiler, and maps the buffer * into memory using tiler. On success, it writes the tiler ID * of the buffer into the area pointed by tiler ID. * * @author a0194118 (9/7/2009) * * @param blks Pointer to array of block info structures * @param num_blocks Number of blocks * @param tiler_id Pointer to tiler ID. * * @return pointer to the mapped buffer. */ static void *tiler_mmap(struct tiler_block_info *blks, int num_blocks, int buf_type) { IN; /* get size */ int ix; bytes_t size; /* register buffer with tiler */ struct tiler_buf_info buf; buf.num_blocks = num_blocks; /* work on copy in buf */ memcpy(buf.blocks, blks, sizeof(tiler_block_info) * num_blocks); #ifndef STUB_TILER dump_buf(&buf, "==(RBUF)=>"); int ret = ioctl(td, TILIOC_RBUF, &buf); dump_buf(&buf, "<=(RBUF)=="); if (NOT_I(ret,==,0)) return NULL; size = buf.length; #else /* save buffer in stub */ struct tiler_buf_info *buf_c = NEWN(struct tiler_buf_info,2); buf.offset = (uint32_t) buf_c; #endif if (NOT_P(buf.offset,!=,0)) return NULL; /* map blocks to process space */ #ifndef STUB_TILER void *bufPtr = mmap(0, map_size(size, buf.offset), PROT_READ | PROT_WRITE, MAP_SHARED, td, buf.offset & ~(PAGE_SIZE - 1)); if (bufPtr == MAP_FAILED){ bufPtr = NULL; } else { bufPtr += buf.offset & (PAGE_SIZE - 1); } if(0) DP("ptr=%p", bufPtr); #else void *bufPtr = malloc(size + PAGE_SIZE - 1); buf_c[1].blocks[0].ptr = bufPtr; bufPtr = ROUND_UP_TO2POW(bufPtr, PAGE_SIZE); /* P("<= [0x%x]", size); */ /* fill out pointers - this is needed for caching 1D/2D type */ for (size = ix = 0; ix < num_blocks; ix++) { buf.blocks[ix].ptr = bufPtr ? bufPtr + size : bufPtr; size += def_size(blks + ix); } memcpy(buf_c, &buf, sizeof(struct tiler_buf_info)); #endif if (bufPtr != NULL) { /* fill out pointers */ for (size = ix = 0; ix < num_blocks; ix++) { buf.blocks[ix].ptr = bufPtr + size; /* P(" [0x%p]", buf.blocks[ix].ptr); */ size += def_size(blks + ix); #ifdef STUB_TILER buf.blocks[ix].ssptr = (uint32_t) buf.blocks[ix].ptr; #else CHK_I((buf.blocks[ix].ssptr & (PAGE_SIZE - 1)),==,((uint32_t) buf.blocks[ix].ptr & (PAGE_SIZE - 1))); #endif } } /* if failed to map: unregister buffer */ if (NOT_P(bufPtr,!=,NULL) || /* or failed to cache tiler buffer */ NOT_I(buf_cache_add(&buf, buf_type),==,0)) { #ifndef STUB_TILER A_I(ioctl(td, TILIOC_URBUF, &buf),==,0); #else FREE(buf_c); buf.offset = 0; #endif } else { /* update original from local copy */ memcpy(blks, buf.blocks, sizeof(tiler_block_info) * num_blocks); } return R_P(bufPtr); } /** * Checks whether the tiler_block_info is filled in correctly. * Verifies the pixel format, correct length, width and or * height, the length/stride relationship for 1D buffers, and * the correct stride for 2D buffers. Also verifies block size * to be page sized if desired. * * @author a0194118 (9/4/2009) * * @param blk Pointer to the tiler_block_info struct * @param is_page_sized Whether the block needs to be page * sized (fit on whole pages). * @return 0 on success, non-0 error value on failure. */ static int check_block(tiler_block_info *blk, bool is_page_sized) { /* check pixelformat */ if (NOT_I(blk->fmt,>=,PIXEL_FMT_MIN) || NOT_I(blk->fmt,<=,PIXEL_FMT_MAX)) return MEMMGR_ERR_GENERIC; if (blk->fmt == PIXEL_FMT_PAGE) { /* check 1D buffers */ /* length must be multiple of stride if stride > 0 */ if (NOT_I(blk->dim.len,>,0) || (blk->stride && NOT_I(blk->dim.len % blk->stride,==,0))) return MEMMGR_ERR_GENERIC; } else { /* check 2D buffers */ /* check width, height and stride (must be the default stride or 0) */ bytes_t stride = def_stride(blk->dim.area.width * def_bpp(blk->fmt)); if (NOT_I(blk->dim.area.width,>,0) || NOT_I(blk->dim.area.height,>,0) || (blk->stride && NOT_I(blk->stride,==,stride))) return MEMMGR_ERR_GENERIC; } if (is_page_sized && NOT_I(def_size(blk) & (PAGE_SIZE - 1),==,0)) return MEMMGR_ERR_GENERIC; return MEMMGR_ERR_NONE; } /** * Checks whether the block information is correct for map and * alloc operations. Checks the number of blocks, and validity * of each block. Warns if reserved member is not 0. Also * checks if the alignment/offset requirements are consistent * across the buffer * * @author a0194118 (9/7/2009) * * @param blks Pointer to the block info array. * @param num_blocks Number of blocks. * @param num_pagesize_blocks Number of blocks that must be * page sized (these must be in * front) * * @return 0 on success, non-0 error value on failure. */ static int check_blocks(struct tiler_block_info *blks, int num_blocks, int num_pagesize_blocks) { /* check arguments */ if (NOT_I(num_blocks,>,0) || NOT_I(num_blocks,<=,TILER_MAX_NUM_BLOCKS)) return MEMMGR_ERR_GENERIC; /* check block allocation params */ int ix; for (ix = 0; ix < num_blocks; ix++) { struct tiler_block_info *blk = blks + ix; CHK_I(blk->ssptr,==,0); CHK_I(blk->id,==,0); int ret = check_block(blk, ix < num_pagesize_blocks); /* check alignment */ if (!ret) { } if (ret) { DP("for block[%d]", ix); return ret; } } /* set alignment parameters */ return MEMMGR_ERR_NONE; } /** * Resets the ptr and reserved fields of the block info * structures. * * @author a0194118 (9/7/2009) * * @param blks Pointer to the block info array. * @param num_blocks Number of blocks. */ static void reset_blocks(struct tiler_block_info *blks, int num_blocks) { int ix; for (ix = 0; ix < num_blocks; ix++) { blks[ix].ssptr = 0; blks[ix].id = 0; blks[ix].ptr = NULL; } } bytes_t MemMgr_PageSize() { return PAGE_SIZE; } void *MemMgr_Alloc(MemAllocBlock blocks[], int num_blocks) { IN; void *bufPtr = NULL; /* need to access ssptrs */ struct tiler_block_info *blks = (tiler_block_info *) blocks; /* check block allocation params, and state */ if (NOT_I(check_blocks(blks, num_blocks, num_blocks - 1),==,0) || NOT_I(inc_ref(),==,0)) goto DONE; /* ----- begin recoverable portion ----- */ int ix; /* allocate each buffer using tiler driver and initialize block info */ for (ix = 0; ix < num_blocks; ix++) { if (ix) { /* continue offset between pages */ } CHK_I(blks[ix].ptr,==,NULL); if (NOT_I(tiler_alloc(blks + ix),==,0)) goto FAIL_ALLOC; } bufPtr = tiler_mmap(blks, num_blocks, BUF_ALLOCED); if (A_P(bufPtr,!=,0)) goto DONE; /* ------ error handling ------ */ FAIL_ALLOC: while (ix) { tiler_free(blks + --ix); } /* clear ssptr and ptr fields for all blocks */ reset_blocks(blks, num_blocks); A_I(dec_ref(),==,0); DONE: CHK_I(cache_check(),==,0); return R_P(bufPtr); } int MemMgr_Free(void *bufPtr) { IN; int ret = MEMMGR_ERR_GENERIC; struct tiler_buf_info buf; ZERO(buf); /* retrieve registered buffers from vsptr */ /* :NOTE: if this succeeds, Memory Allocator stops tracking this buffer */ buf_cache_del(bufPtr, &buf, BUF_ALLOCED); if (A_L(buf.offset,!=,0)) { #ifndef STUB_TILER dump_buf(&buf, "==(URBUF)=>"); ret = A_I(ioctl(td, TILIOC_URBUF, &buf),==,0); dump_buf(&buf, "<=(URBUF)=="); /* free each block */ int ix; for (ix = 0; ix < buf.num_blocks; ix++) { ERR_ADD(ret, tiler_free(buf.blocks + ix)); } /* unmap buffer */ bufPtr = (void *)((uint32_t)bufPtr & ~(PAGE_SIZE - 1)); ERR_ADD(ret, munmap(bufPtr, map_size(buf.length, buf.offset))); #else void *ptr = (void *) buf.offset; FREE(ptr); ret = MEMMGR_ERR_NONE; #endif ERR_ADD(ret, dec_ref()); } CHK_I(cache_check(),==,0); return R_I(ret); } void *MemMgr_Map(MemAllocBlock blocks[], int num_blocks) { IN; void *bufPtr = NULL; /* need to access ssptrs */ struct tiler_block_info *blks = (tiler_block_info *) blocks; /* check block params, and state */ if (check_blocks(blks, num_blocks, num_blocks) || NOT_I(inc_ref(),==,0)) goto DONE; /* we only map 1 page aligned 1D buffer for now */ if (NOT_I(num_blocks,==,1) || NOT_I(blocks[0].pixelFormat,==,PIXEL_FMT_PAGE) || NOT_I(blocks[0].dim.len & (PAGE_SIZE - 1),==,0) || #ifdef STUB_TILER NOT_I(MemMgr_IsMapped(blocks[0].ptr),==,0) || #endif NOT_I((uint32_t)blocks[0].ptr & (PAGE_SIZE - 1),==,0)) goto FAIL; /* ----- begin recoverable portion ----- */ int ix; /* allocate each buffer using tiler driver */ for (ix = 0; ix < num_blocks; ix++) { if (ix) { /* continue offset between pages */ } if (NOT_I(blks[ix].ptr,!=,NULL) || NOT_I(tiler_map(blks + ix),==,0)) goto FAIL_MAP; } /* map bufer into tiler space and register with tiler manager */ bufPtr = tiler_mmap(blks, num_blocks, BUF_MAPPED); if (A_P(bufPtr,!=,0)) goto DONE; /* ------ error handling ------ */ FAIL_MAP: while (ix) { tiler_unmap(blks + --ix); } FAIL: /* clear ssptr and ptr fields for all blocks */ reset_blocks(blks, num_blocks); A_I(dec_ref(),==,0); DONE: CHK_I(cache_check(),==,0); return R_P(bufPtr); } int MemMgr_UnMap(void *bufPtr) { IN; int ret = MEMMGR_ERR_GENERIC; struct tiler_buf_info buf; ZERO(buf); /* retrieve registered buffers from vsptr */ /* :NOTE: if this succeeds, Memory Allocator stops tracking this buffer */ buf_cache_del(bufPtr, &buf, BUF_MAPPED); if (A_L(buf.offset,!=,0)) { #ifndef STUB_TILER dump_buf(&buf, "==(URBUF)=>"); ret = A_I(ioctl(td, TILIOC_URBUF, &buf),==,0); dump_buf(&buf, "<=(URBUF)=="); /* unmap each block */ int ix; for (ix = 0; ix < buf.num_blocks; ix++) { ERR_ADD(ret, tiler_unmap(buf.blocks + ix)); } /* unmap buffer */ bufPtr = (void *)((uint32_t)bufPtr & ~(PAGE_SIZE - 1)); ERR_ADD(ret, munmap(bufPtr, map_size(buf.length, buf.offset))); #else struct tiler_buf_info *ptr = (struct tiler_buf_info *) buf.offset; FREE(ptr[1].blocks[0].ptr); FREE(ptr); ret = MEMMGR_ERR_NONE; #endif ERR_ADD(ret, dec_ref()); } CHK_I(cache_check(),==,0); return R_I(ret); } bool MemMgr_Is1DBlock(void *ptr) { IN; SSPtr ssptr = TilerMem_VirtToPhys(ptr); enum tiler_fmt fmt = tiler_get_fmt(ssptr); return R_I(fmt == TILFMT_PAGE); } bool MemMgr_Is2DBlock(void *ptr) { IN; SSPtr ssptr = TilerMem_VirtToPhys(ptr); enum tiler_fmt fmt = tiler_get_fmt(ssptr); return R_I(fmt == TILFMT_8BIT || fmt == TILFMT_16BIT || fmt == TILFMT_32BIT); } bool MemMgr_IsMapped(void *ptr) { IN; SSPtr ssptr = TilerMem_VirtToPhys(ptr); enum tiler_fmt fmt = tiler_get_fmt(ssptr); return R_I(fmt == TILFMT_8BIT || fmt == TILFMT_16BIT || fmt == TILFMT_32BIT || fmt == TILFMT_PAGE); } bytes_t MemMgr_GetStride(void *ptr) { IN; #ifndef STUB_TILER struct tiler_buf_info buf; ZERO(buf); /* find block that this buffer belongs to */ buf_cache_query(ptr, &buf, BUF_ALLOCED | BUF_MAPPED); void *bufPtr = buf.blocks[0].ptr; A_I(inc_ref(),==,0); /* for tiler mapped buffers, get saved stride information */ if (buf.offset) { /* walk through block to determine which stride we need */ int ix; for (ix = 0; ix < buf.num_blocks; ix++) { bytes_t size = def_size(buf.blocks + ix); if (bufPtr <= ptr && ptr < bufPtr + size) { A_I(dec_ref(),==,0); return R_UP(buf.blocks[ix].stride); } bufPtr += size; } A_I(dec_ref(),==,0); DP("assert: should not ever get here"); return R_UP(0); } /* see if pointer is valid */ else if (TilerMem_VirtToPhys(ptr) == 0) { A_I(dec_ref(),==,0); return R_UP(0); } A_I(dec_ref(),==,0); #else /* if emulating, we need to get through all allocated memory segments */ pthread_mutex_lock(&che_mutex); init(); _AllocData *ad; if (!ptr) return R_UP(0); DLIST_MLOOP(bufs, ad, link) { int ix; struct tiler_buf_info *buf = (struct tiler_buf_info *) ad->buf.offset; for (ix = 0; ix < buf->num_blocks; ix++) { if (ptr >= buf->blocks[ix].ptr && ptr < buf->blocks[ix].ptr + def_size(buf->blocks + ix)) { bytes_t stride = buf->blocks[ix].stride; pthread_mutex_unlock(&che_mutex); return R_UP(stride); } } } pthread_mutex_unlock(&che_mutex); #endif return R_UP(PAGE_SIZE); } bytes_t TilerMem_GetStride(SSPtr ssptr) { IN; switch(tiler_get_fmt(ssptr)) { case TILFMT_8BIT: return R_UP(TILER_STRIDE_8BIT); case TILFMT_16BIT: return R_UP(TILER_STRIDE_16BIT); case TILFMT_32BIT: return R_UP(TILER_STRIDE_32BIT); case TILFMT_PAGE: return R_UP(PAGE_SIZE); default: return R_UP(0); } } SSPtr TilerMem_VirtToPhys(void *ptr) { #ifndef STUB_TILER SSPtr ssptr = 0; if(!NOT_I(inc_ref(),==,0)) { ssptr = ioctl(td, TILIOC_GSSP, (unsigned long) ptr); A_I(dec_ref(),==,0); } return (SSPtr)R_P(ssptr); #else return (SSPtr)ptr; #endif } /** * Internal Unit Test. Tests the static methods of this * library. Assumes an unitialized state as well. * * @author a0194118 (9/4/2009) * * @return 0 for success, non-0 error value for failure. */ int __test__MemMgr() { int ret = 0; /* state check */ ret |= NOT_I(TILER_PAGE_WIDTH * TILER_PAGE_HEIGHT,==,PAGE_SIZE); ret |= NOT_I(refCnt,==,0); ret |= NOT_I(inc_ref(),==,0); ret |= NOT_I(refCnt,==,1); ret |= NOT_I(dec_ref(),==,0); ret |= NOT_I(refCnt,==,0); /* enumeration check */ ret |= NOT_I(PIXEL_FMT_8BIT,==,TILFMT_8BIT); ret |= NOT_I(PIXEL_FMT_16BIT,==,TILFMT_16BIT); ret |= NOT_I(PIXEL_FMT_32BIT,==,TILFMT_32BIT); ret |= NOT_I(PIXEL_FMT_PAGE,==,TILFMT_PAGE); ret |= NOT_I(sizeof(MemAllocBlock),==,sizeof(struct tiler_block_info)); /* void * arithmetic */ void *a = (void *)1000, *b = a + 2000, *c = (void *)3000; ret |= NOT_P(b,==,c); /* def_stride */ ret |= NOT_I(def_stride(0),==,0); ret |= NOT_I(def_stride(1),==,PAGE_SIZE); ret |= NOT_I(def_stride(PAGE_SIZE),==,PAGE_SIZE); ret |= NOT_I(def_stride(PAGE_SIZE + 1),==,2 * PAGE_SIZE); /* def_bpp */ ret |= NOT_I(def_bpp(PIXEL_FMT_32BIT),==,4); ret |= NOT_I(def_bpp(PIXEL_FMT_16BIT),==,2); ret |= NOT_I(def_bpp(PIXEL_FMT_8BIT),==,1); /* def_size */ tiler_block_info blk = {0}; blk.fmt = TILFMT_8BIT; blk.dim.area.width = PAGE_SIZE * 8 / 10; blk.dim.area.height = 10; ret |= NOT_I(def_size(&blk),==,10 * PAGE_SIZE); blk.fmt = TILFMT_16BIT; blk.dim.area.width = PAGE_SIZE * 7 / 10; ret |= NOT_I(def_size(&blk),==,20 * PAGE_SIZE); blk.dim.area.width = PAGE_SIZE * 4 / 10; ret |= NOT_I(def_size(&blk),==,10 * PAGE_SIZE); blk.fmt = TILFMT_32BIT; ret |= NOT_I(def_size(&blk),==,20 * PAGE_SIZE); blk.dim.area.width = PAGE_SIZE * 6 / 10; ret |= NOT_I(def_size(&blk),==,30 * PAGE_SIZE); return ret; }