/* Copyright (c) 2002,2007-2010, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * */ #include "gsl.h" #include "gsl_hal.h" ///////////////////////////////////////////////////////////////////////////// // macros ////////////////////////////////////////////////////////////////////////////// #define GSL_SHMEM_APERTURE_MARK(aperture_id) \ (shmem->priv |= (((aperture_id + 1) << GSL_APERTURE_SHIFT) & GSL_APERTURE_MASK)) #define GSL_SHMEM_APERTURE_ISMARKED(aperture_id) \ (((shmem->priv & GSL_APERTURE_MASK) >> GSL_APERTURE_SHIFT) & (aperture_id + 1)) #define GSL_MEMFLAGS_APERTURE_GET(flags, aperture_id) \ aperture_id = (gsl_apertureid_t)((flags & GSL_MEMFLAGS_APERTURE_MASK) >> GSL_MEMFLAGS_APERTURE_SHIFT); \ KOS_ASSERT(aperture_id < GSL_APERTURE_MAX); #define GSL_MEMFLAGS_CHANNEL_GET(flags, channel_id) \ channel_id = (gsl_channelid_t)((flags & GSL_MEMFLAGS_CHANNEL_MASK) >> GSL_MEMFLAGS_CHANNEL_SHIFT); \ KOS_ASSERT(channel_id < GSL_CHANNEL_MAX); #define GSL_MEMDESC_APERTURE_SET(memdesc, aperture_index) \ memdesc->priv = (memdesc->priv & ~GSL_APERTURE_MASK) | ((aperture_index << GSL_APERTURE_SHIFT) & GSL_APERTURE_MASK); #define GSL_MEMDESC_DEVICE_SET(memdesc, device_id) \ memdesc->priv = (memdesc->priv & ~GSL_DEVICEID_MASK) | ((device_id << GSL_DEVICEID_SHIFT) & GSL_DEVICEID_MASK); #define GSL_MEMDESC_EXTALLOC_SET(memdesc, flag) \ memdesc->priv = (memdesc->priv & ~GSL_EXTALLOC_MASK) | ((flag << GSL_EXTALLOC_SHIFT) & GSL_EXTALLOC_MASK); #define GSL_MEMDESC_APERTURE_GET(memdesc, aperture_index) \ KOS_ASSERT(memdesc); \ aperture_index = ((memdesc->priv & GSL_APERTURE_MASK) >> GSL_APERTURE_SHIFT); \ KOS_ASSERT(aperture_index < GSL_SHMEM_MAX_APERTURES); #define GSL_MEMDESC_DEVICE_GET(memdesc, device_id) \ KOS_ASSERT(memdesc); \ device_id = (gsl_deviceid_t)((memdesc->priv & GSL_DEVICEID_MASK) >> GSL_DEVICEID_SHIFT); \ KOS_ASSERT(device_id <= GSL_DEVICE_MAX); #define GSL_MEMDESC_EXTALLOC_ISMARKED(memdesc) \ ((memdesc->priv & GSL_EXTALLOC_MASK) >> GSL_EXTALLOC_SHIFT) ////////////////////////////////////////////////////////////////////////////// // aperture index in shared memory object ////////////////////////////////////////////////////////////////////////////// OSINLINE int kgsl_sharedmem_getapertureindex(gsl_sharedmem_t *shmem, gsl_apertureid_t aperture_id, gsl_channelid_t channel_id) { KOS_ASSERT(shmem->aperturelookup[aperture_id][channel_id] < shmem->numapertures); return (shmem->aperturelookup[aperture_id][channel_id]); } ////////////////////////////////////////////////////////////////////////////// // functions ////////////////////////////////////////////////////////////////////////////// int kgsl_sharedmem_init(gsl_sharedmem_t *shmem) { int i; int status; gsl_shmemconfig_t config; int mmu_virtualized; gsl_apertureid_t aperture_id; gsl_channelid_t channel_id; unsigned int hostbaseaddr; gpuaddr_t gpubaseaddr; int sizebytes; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_init(gsl_sharedmem_t *shmem=0x%08x)\n", shmem ); if (shmem->flags & GSL_FLAGS_INITIALIZED) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_init. Return value %B\n", GSL_SUCCESS ); return (GSL_SUCCESS); } status = kgsl_hal_getshmemconfig(&config); if (status != GSL_SUCCESS) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Unable to get sharedmem config.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_init. Return value %B\n", status ); return (status); } shmem->numapertures = config.numapertures; for (i = 0; i < shmem->numapertures; i++) { aperture_id = config.apertures[i].id; channel_id = config.apertures[i].channel; hostbaseaddr = config.apertures[i].hostbase; gpubaseaddr = config.apertures[i].gpubase; sizebytes = config.apertures[i].sizebytes; mmu_virtualized = 0; // handle mmu virtualized aperture if (aperture_id == GSL_APERTURE_MMU) { mmu_virtualized = 1; aperture_id = GSL_APERTURE_EMEM; } // make sure aligned to page size KOS_ASSERT((gpubaseaddr & ((1 << GSL_PAGESIZE_SHIFT) - 1)) == 0); // make a multiple of page size sizebytes = (sizebytes & ~((1 << GSL_PAGESIZE_SHIFT) - 1)); if (sizebytes > 0) { shmem->apertures[i].memarena = kgsl_memarena_create(aperture_id, mmu_virtualized, hostbaseaddr, gpubaseaddr, sizebytes); if (!shmem->apertures[i].memarena) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Unable to allocate memarena.\n" ); kgsl_sharedmem_close(shmem); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_init. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } shmem->apertures[i].id = aperture_id; shmem->apertures[i].channel = channel_id; shmem->apertures[i].numbanks = 1; // create aperture lookup table if (GSL_SHMEM_APERTURE_ISMARKED(aperture_id)) { // update "current aperture_id"/"current channel_id" index shmem->aperturelookup[aperture_id][channel_id] = i; } else { // initialize "current aperture_id"/"channel_id" indexes for (channel_id = GSL_CHANNEL_1; channel_id < GSL_CHANNEL_MAX; channel_id++) { shmem->aperturelookup[aperture_id][channel_id] = i; } GSL_SHMEM_APERTURE_MARK(aperture_id); } } } shmem->flags |= GSL_FLAGS_INITIALIZED; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_init. Return value %B\n", GSL_SUCCESS ); return (GSL_SUCCESS); } //---------------------------------------------------------------------------- int kgsl_sharedmem_close(gsl_sharedmem_t *shmem) { int i; int result = GSL_SUCCESS; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_close(gsl_sharedmem_t *shmem=0x%08x)\n", shmem ); if (shmem->flags & GSL_FLAGS_INITIALIZED) { for (i = 0; i < shmem->numapertures; i++) { if (shmem->apertures[i].memarena) { result = kgsl_memarena_destroy(shmem->apertures[i].memarena); } } kos_memset(shmem, 0, sizeof(gsl_sharedmem_t)); } kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_close. Return value %B\n", result ); return (result); } //---------------------------------------------------------------------------- int kgsl_sharedmem_alloc0(gsl_deviceid_t device_id, gsl_flags_t flags, int sizebytes, gsl_memdesc_t *memdesc) { gsl_apertureid_t aperture_id; gsl_channelid_t channel_id; gsl_deviceid_t tmp_id; int aperture_index, org_index; int result = GSL_FAILURE; gsl_mmu_t *mmu = NULL; gsl_sharedmem_t *shmem = &gsl_driver.shmem; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_alloc(gsl_deviceid_t device_id=%D, gsl_flags_t flags=0x%08x, int sizebytes=%d, gsl_memdesc_t *memdesc=%M)\n", device_id, flags, sizebytes, memdesc ); KOS_ASSERT(sizebytes); KOS_ASSERT(memdesc); GSL_MEMFLAGS_APERTURE_GET(flags, aperture_id); GSL_MEMFLAGS_CHANNEL_GET(flags, channel_id); kos_memset(memdesc, 0, sizeof(gsl_memdesc_t)); if (!(shmem->flags & GSL_FLAGS_INITIALIZED)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Shared memory not initialized.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_alloc. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } // execute pending device action tmp_id = (device_id != GSL_DEVICE_ANY) ? device_id : device_id+1; for ( ; tmp_id <= GSL_DEVICE_MAX; tmp_id++) { if (gsl_driver.device[tmp_id-1].flags & GSL_FLAGS_INITIALIZED) { kgsl_device_runpending(&gsl_driver.device[tmp_id-1]); if (tmp_id == device_id) { break; } } } // convert any device to an actual existing device if (device_id == GSL_DEVICE_ANY) { for ( ; ; ) { device_id++; if (device_id <= GSL_DEVICE_MAX) { if (gsl_driver.device[device_id-1].flags & GSL_FLAGS_INITIALIZED) { break; } } else { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Invalid device.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_alloc. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } } } KOS_ASSERT(device_id > GSL_DEVICE_ANY && device_id <= GSL_DEVICE_MAX); // get mmu reference mmu = &gsl_driver.device[device_id-1].mmu; aperture_index = kgsl_sharedmem_getapertureindex(shmem, aperture_id, channel_id); //do not proceed if it is a strict request, the aperture requested is not present, and the MMU is enabled if (!((flags & GSL_MEMFLAGS_STRICTREQUEST) && aperture_id != shmem->apertures[aperture_index].id && kgsl_mmu_isenabled(mmu))) { // do allocation result = kgsl_memarena_alloc(shmem->apertures[aperture_index].memarena, flags, sizebytes, memdesc); // if allocation failed if (result != GSL_SUCCESS) { org_index = aperture_index; // then failover to other channels within the current aperture for (channel_id = GSL_CHANNEL_1; channel_id < GSL_CHANNEL_MAX; channel_id++) { aperture_index = kgsl_sharedmem_getapertureindex(shmem, aperture_id, channel_id); if (aperture_index != org_index) { // do allocation result = kgsl_memarena_alloc(shmem->apertures[aperture_index].memarena, flags, sizebytes, memdesc); if (result == GSL_SUCCESS) { break; } } } // if allocation still has not succeeded, then failover to EMEM/MMU aperture, but // not if it's a strict request and the MMU is enabled if (result != GSL_SUCCESS && aperture_id != GSL_APERTURE_EMEM && !((flags & GSL_MEMFLAGS_STRICTREQUEST) && kgsl_mmu_isenabled(mmu))) { aperture_id = GSL_APERTURE_EMEM; // try every channel for (channel_id = GSL_CHANNEL_1; channel_id < GSL_CHANNEL_MAX; channel_id++) { aperture_index = kgsl_sharedmem_getapertureindex(shmem, aperture_id, channel_id); if (aperture_index != org_index) { // do allocation result = kgsl_memarena_alloc(shmem->apertures[aperture_index].memarena, flags, sizebytes, memdesc); if (result == GSL_SUCCESS) { break; } } } } } } if (result == GSL_SUCCESS) { GSL_MEMDESC_APERTURE_SET(memdesc, aperture_index); GSL_MEMDESC_DEVICE_SET(memdesc, device_id); if (kgsl_memarena_isvirtualized(shmem->apertures[aperture_index].memarena)) { gsl_scatterlist_t scatterlist; scatterlist.contiguous = 0; scatterlist.num = memdesc->size / GSL_PAGESIZE; if (memdesc->size & (GSL_PAGESIZE-1)) { scatterlist.num++; } scatterlist.pages = kos_malloc(sizeof(unsigned int) * scatterlist.num); if (scatterlist.pages) { // allocate physical pages result = kgsl_hal_allocphysical(memdesc->gpuaddr, scatterlist.num, scatterlist.pages); if (result == GSL_SUCCESS) { result = kgsl_mmu_map(mmu, memdesc->gpuaddr, &scatterlist, flags, GSL_CALLER_PROCESSID_GET()); if (result != GSL_SUCCESS) { kgsl_hal_freephysical(memdesc->gpuaddr, scatterlist.num, scatterlist.pages); } } kos_free(scatterlist.pages); } else { result = GSL_FAILURE; } if (result != GSL_SUCCESS) { kgsl_memarena_free(shmem->apertures[aperture_index].memarena, memdesc); } } } KGSL_DEBUG_TBDUMP_SETMEM( memdesc->gpuaddr, 0, memdesc->size ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_alloc. Return value %B\n", result ); return (result); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_alloc(gsl_deviceid_t device_id, gsl_flags_t flags, int sizebytes, gsl_memdesc_t *memdesc) { int status = GSL_SUCCESS; GSL_API_MUTEX_LOCK(); status = kgsl_sharedmem_alloc0(device_id, flags, sizebytes, memdesc); GSL_API_MUTEX_UNLOCK(); return status; } //---------------------------------------------------------------------------- int kgsl_sharedmem_free0(gsl_memdesc_t *memdesc, unsigned int pid) { int status = GSL_SUCCESS; int aperture_index; gsl_deviceid_t device_id; gsl_sharedmem_t *shmem; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_free(gsl_memdesc_t *memdesc=%M)\n", memdesc ); GSL_MEMDESC_APERTURE_GET(memdesc, aperture_index); GSL_MEMDESC_DEVICE_GET(memdesc, device_id); shmem = &gsl_driver.shmem; if (shmem->flags & GSL_FLAGS_INITIALIZED) { if (kgsl_memarena_isvirtualized(shmem->apertures[aperture_index].memarena)) { status |= kgsl_mmu_unmap(&gsl_driver.device[device_id-1].mmu, memdesc->gpuaddr, memdesc->size, pid); if (!GSL_MEMDESC_EXTALLOC_ISMARKED(memdesc)) { status |= kgsl_hal_freephysical(memdesc->gpuaddr, memdesc->size / GSL_PAGESIZE, NULL); } } kgsl_memarena_free(shmem->apertures[aperture_index].memarena, memdesc); // clear descriptor kos_memset(memdesc, 0, sizeof(gsl_memdesc_t)); } else { status = GSL_FAILURE; } kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_free. Return value %B\n", status ); return (status); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_free(gsl_memdesc_t *memdesc) { int status = GSL_SUCCESS; GSL_API_MUTEX_LOCK(); status = kgsl_sharedmem_free0(memdesc, GSL_CALLER_PROCESSID_GET()); GSL_API_MUTEX_UNLOCK(); return status; } //---------------------------------------------------------------------------- int kgsl_sharedmem_read0(const gsl_memdesc_t *memdesc, void *dst, unsigned int offsetbytes, unsigned int sizebytes, unsigned int touserspace) { int aperture_index; gsl_sharedmem_t *shmem; unsigned int gpuoffsetbytes; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_read(gsl_memdesc_t *memdesc=%M, void *dst=0x%08x, unsigned int offsetbytes=%d, unsigned int sizebytes=%d)\n", memdesc, dst, offsetbytes, sizebytes ); GSL_MEMDESC_APERTURE_GET(memdesc, aperture_index); if (GSL_MEMDESC_EXTALLOC_ISMARKED(memdesc)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_read. Return value %B\n", GSL_FAILURE_BADPARAM ); return (GSL_FAILURE_BADPARAM); } shmem = &gsl_driver.shmem; if (!(shmem->flags & GSL_FLAGS_INITIALIZED)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Shared memory not initialized.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_read. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } KOS_ASSERT(dst); KOS_ASSERT(sizebytes); if (memdesc->gpuaddr < shmem->apertures[aperture_index].memarena->gpubaseaddr) { return (GSL_FAILURE_BADPARAM); } if (memdesc->gpuaddr + sizebytes > shmem->apertures[aperture_index].memarena->gpubaseaddr + shmem->apertures[aperture_index].memarena->sizebytes) { return (GSL_FAILURE_BADPARAM); } gpuoffsetbytes = (memdesc->gpuaddr - shmem->apertures[aperture_index].memarena->gpubaseaddr) + offsetbytes; GSL_HAL_MEM_READ(dst, shmem->apertures[aperture_index].memarena->hostbaseaddr, gpuoffsetbytes, sizebytes, touserspace); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_read. Return value %B\n", GSL_SUCCESS ); return (GSL_SUCCESS); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_read(const gsl_memdesc_t *memdesc, void *dst, unsigned int offsetbytes, unsigned int sizebytes, unsigned int touserspace) { int status = GSL_SUCCESS; GSL_API_MUTEX_LOCK(); status = kgsl_sharedmem_read0(memdesc, dst, offsetbytes, sizebytes, touserspace); GSL_API_MUTEX_UNLOCK(); return status; } //---------------------------------------------------------------------------- int kgsl_sharedmem_write0(const gsl_memdesc_t *memdesc, unsigned int offsetbytes, void *src, unsigned int sizebytes, unsigned int fromuserspace) { int aperture_index; gsl_sharedmem_t *shmem; unsigned int gpuoffsetbytes; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_write(gsl_memdesc_t *memdesc=%M, unsigned int offsetbytes=%d, void *src=0x%08x, unsigned int sizebytes=%d)\n", memdesc, offsetbytes, src, sizebytes ); GSL_MEMDESC_APERTURE_GET(memdesc, aperture_index); if (GSL_MEMDESC_EXTALLOC_ISMARKED(memdesc)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_write. Return value %B\n", GSL_FAILURE_BADPARAM ); return (GSL_FAILURE_BADPARAM); } shmem = &gsl_driver.shmem; if (!(shmem->flags & GSL_FLAGS_INITIALIZED)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Shared memory not initialized.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_write. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } KOS_ASSERT(src); KOS_ASSERT(sizebytes); KOS_ASSERT(memdesc->gpuaddr >= shmem->apertures[aperture_index].memarena->gpubaseaddr); KOS_ASSERT((memdesc->gpuaddr + sizebytes) <= (shmem->apertures[aperture_index].memarena->gpubaseaddr + shmem->apertures[aperture_index].memarena->sizebytes)); gpuoffsetbytes = (memdesc->gpuaddr - shmem->apertures[aperture_index].memarena->gpubaseaddr) + offsetbytes; GSL_HAL_MEM_WRITE(shmem->apertures[aperture_index].memarena->hostbaseaddr, gpuoffsetbytes, src, sizebytes, fromuserspace); KGSL_DEBUG(GSL_DBGFLAGS_PM4MEM, KGSL_DEBUG_DUMPMEMWRITE((memdesc->gpuaddr + offsetbytes), sizebytes, src)); KGSL_DEBUG_TBDUMP_SYNCMEM( (memdesc->gpuaddr + offsetbytes), src, sizebytes ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_write. Return value %B\n", GSL_SUCCESS ); return (GSL_SUCCESS); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_write(const gsl_memdesc_t *memdesc, unsigned int offsetbytes, void *src, unsigned int sizebytes, unsigned int fromuserspace) { int status = GSL_SUCCESS; GSL_API_MUTEX_LOCK(); status = kgsl_sharedmem_write0(memdesc, offsetbytes, src, sizebytes, fromuserspace); GSL_API_MUTEX_UNLOCK(); return status; } //---------------------------------------------------------------------------- int kgsl_sharedmem_set0(const gsl_memdesc_t *memdesc, unsigned int offsetbytes, unsigned int value, unsigned int sizebytes) { int aperture_index; gsl_sharedmem_t *shmem; unsigned int gpuoffsetbytes; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_set(gsl_memdesc_t *memdesc=%M, unsigned int offsetbytes=%d, unsigned int value=0x%08x, unsigned int sizebytes=%d)\n", memdesc, offsetbytes, value, sizebytes ); GSL_MEMDESC_APERTURE_GET(memdesc, aperture_index); if (GSL_MEMDESC_EXTALLOC_ISMARKED(memdesc)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_set. Return value %B\n", GSL_FAILURE_BADPARAM ); return (GSL_FAILURE_BADPARAM); } shmem = &gsl_driver.shmem; if (!(shmem->flags & GSL_FLAGS_INITIALIZED)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Shared memory not initialized.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_set. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } KOS_ASSERT(sizebytes); KOS_ASSERT(memdesc->gpuaddr >= shmem->apertures[aperture_index].memarena->gpubaseaddr); KOS_ASSERT((memdesc->gpuaddr + sizebytes) <= (shmem->apertures[aperture_index].memarena->gpubaseaddr + shmem->apertures[aperture_index].memarena->sizebytes)); gpuoffsetbytes = (memdesc->gpuaddr - shmem->apertures[aperture_index].memarena->gpubaseaddr) + offsetbytes; GSL_HAL_MEM_SET(shmem->apertures[aperture_index].memarena->hostbaseaddr, gpuoffsetbytes, value, sizebytes); KGSL_DEBUG(GSL_DBGFLAGS_PM4MEM, KGSL_DEBUG_DUMPMEMSET((memdesc->gpuaddr + offsetbytes), sizebytes, value)); KGSL_DEBUG_TBDUMP_SETMEM( (memdesc->gpuaddr + offsetbytes), value, sizebytes ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_set. Return value %B\n", GSL_SUCCESS ); return (GSL_SUCCESS); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_set(const gsl_memdesc_t *memdesc, unsigned int offsetbytes, unsigned int value, unsigned int sizebytes) { int status = GSL_SUCCESS; GSL_API_MUTEX_LOCK(); status = kgsl_sharedmem_set0(memdesc, offsetbytes, value, sizebytes); GSL_API_MUTEX_UNLOCK(); return status; } //---------------------------------------------------------------------------- KGSL_API unsigned int kgsl_sharedmem_largestfreeblock(gsl_deviceid_t device_id, gsl_flags_t flags) { gsl_apertureid_t aperture_id; gsl_channelid_t channel_id; int aperture_index; unsigned int result = 0; gsl_sharedmem_t *shmem; // device_id is ignored at this level, it would be used with per-device memarena's // unreferenced formal parameter (void) device_id; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_largestfreeblock(gsl_deviceid_t device_id=%D, gsl_flags_t flags=0x%08x)\n", device_id, flags ); GSL_MEMFLAGS_APERTURE_GET(flags, aperture_id); GSL_MEMFLAGS_CHANNEL_GET(flags, channel_id); GSL_API_MUTEX_LOCK(); shmem = &gsl_driver.shmem; if (!(shmem->flags & GSL_FLAGS_INITIALIZED)) { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Shared memory not initialized.\n" ); GSL_API_MUTEX_UNLOCK(); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_largestfreeblock. Return value %d\n", 0 ); return (0); } aperture_index = kgsl_sharedmem_getapertureindex(shmem, aperture_id, channel_id); if (aperture_id == shmem->apertures[aperture_index].id) { result = kgsl_memarena_getlargestfreeblock(shmem->apertures[aperture_index].memarena, flags); } GSL_API_MUTEX_UNLOCK(); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_largestfreeblock. Return value %d\n", result ); return (result); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_map(gsl_deviceid_t device_id, gsl_flags_t flags, const gsl_scatterlist_t *scatterlist, gsl_memdesc_t *memdesc) { int status = GSL_FAILURE; gsl_sharedmem_t *shmem = &gsl_driver.shmem; int aperture_index; gsl_deviceid_t tmp_id; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_map(gsl_deviceid_t device_id=%D, gsl_flags_t flags=0x%08x, gsl_scatterlist_t scatterlist=%M, gsl_memdesc_t *memdesc=%M)\n", device_id, flags, memdesc, scatterlist ); // execute pending device action tmp_id = (device_id != GSL_DEVICE_ANY) ? device_id : device_id+1; for ( ; tmp_id <= GSL_DEVICE_MAX; tmp_id++) { if (gsl_driver.device[tmp_id-1].flags & GSL_FLAGS_INITIALIZED) { kgsl_device_runpending(&gsl_driver.device[tmp_id-1]); if (tmp_id == device_id) { break; } } } // convert any device to an actual existing device if (device_id == GSL_DEVICE_ANY) { for ( ; ; ) { device_id++; if (device_id <= GSL_DEVICE_MAX) { if (gsl_driver.device[device_id-1].flags & GSL_FLAGS_INITIALIZED) { break; } } else { kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_ERROR, "ERROR: Invalid device.\n" ); kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_map. Return value %B\n", GSL_FAILURE ); return (GSL_FAILURE); } } } KOS_ASSERT(device_id > GSL_DEVICE_ANY && device_id <= GSL_DEVICE_MAX); if (shmem->flags & GSL_FLAGS_INITIALIZED) { aperture_index = kgsl_sharedmem_getapertureindex(shmem, GSL_APERTURE_EMEM, GSL_CHANNEL_1); if (kgsl_memarena_isvirtualized(shmem->apertures[aperture_index].memarena)) { KOS_ASSERT(scatterlist->num); KOS_ASSERT(scatterlist->pages); status = kgsl_memarena_alloc(shmem->apertures[aperture_index].memarena, flags, scatterlist->num *GSL_PAGESIZE, memdesc); if (status == GSL_SUCCESS) { GSL_MEMDESC_APERTURE_SET(memdesc, aperture_index); GSL_MEMDESC_DEVICE_SET(memdesc, device_id); // mark descriptor's memory as externally allocated -- i.e. outside GSL GSL_MEMDESC_EXTALLOC_SET(memdesc, 1); status = kgsl_mmu_map(&gsl_driver.device[device_id-1].mmu, memdesc->gpuaddr, scatterlist, flags, GSL_CALLER_PROCESSID_GET()); if (status != GSL_SUCCESS) { kgsl_memarena_free(shmem->apertures[aperture_index].memarena, memdesc); } } } } kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_map. Return value %B\n", status ); return (status); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_unmap(gsl_memdesc_t *memdesc) { return (kgsl_sharedmem_free0(memdesc, GSL_CALLER_PROCESSID_GET())); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_getmap(const gsl_memdesc_t *memdesc, gsl_scatterlist_t *scatterlist) { int status = GSL_SUCCESS; int aperture_index; gsl_deviceid_t device_id; gsl_sharedmem_t *shmem; kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "--> int kgsl_sharedmem_getmap(gsl_memdesc_t *memdesc=%M, gsl_scatterlist_t scatterlist=%M)\n", memdesc, scatterlist ); GSL_MEMDESC_APERTURE_GET(memdesc, aperture_index); GSL_MEMDESC_DEVICE_GET(memdesc, device_id); shmem = &gsl_driver.shmem; if (shmem->flags & GSL_FLAGS_INITIALIZED) { KOS_ASSERT(scatterlist->num); KOS_ASSERT(scatterlist->pages); KOS_ASSERT(memdesc->gpuaddr >= shmem->apertures[aperture_index].memarena->gpubaseaddr); KOS_ASSERT((memdesc->gpuaddr + memdesc->size) <= (shmem->apertures[aperture_index].memarena->gpubaseaddr + shmem->apertures[aperture_index].memarena->sizebytes)); kos_memset(scatterlist->pages, 0, sizeof(unsigned int) * scatterlist->num); if (kgsl_memarena_isvirtualized(shmem->apertures[aperture_index].memarena)) { status = kgsl_mmu_getmap(&gsl_driver.device[device_id-1].mmu, memdesc->gpuaddr, memdesc->size, scatterlist, GSL_CALLER_PROCESSID_GET()); } else { // coalesce physically contiguous pages into a single scatter list entry scatterlist->pages[0] = memdesc->gpuaddr; scatterlist->contiguous = 1; } } kgsl_log_write( KGSL_LOG_GROUP_MEMORY | KGSL_LOG_LEVEL_TRACE, "<-- kgsl_sharedmem_getmap. Return value %B\n", status ); return (status); } //---------------------------------------------------------------------------- int kgsl_sharedmem_querystats(gsl_sharedmem_t *shmem, gsl_sharedmem_stats_t *stats) { #ifdef GSL_STATS_MEM int status = GSL_SUCCESS; int i; KOS_ASSERT(stats); if (shmem->flags & GSL_FLAGS_INITIALIZED) { for (i = 0; i < shmem->numapertures; i++) { if (shmem->apertures[i].memarena) { stats->apertures[i].id = shmem->apertures[i].id; stats->apertures[i].channel = shmem->apertures[i].channel; status |= kgsl_memarena_querystats(shmem->apertures[i].memarena, &stats->apertures[i].memarena); } } } else { kos_memset(stats, 0, sizeof(gsl_sharedmem_stats_t)); } return (status); #else // unreferenced formal parameters (void) shmem; (void) stats; return (GSL_FAILURE_NOTSUPPORTED); #endif // GSL_STATS_MEM } //---------------------------------------------------------------------------- unsigned int kgsl_sharedmem_convertaddr(unsigned int addr, int type) { gsl_sharedmem_t *shmem = &gsl_driver.shmem; unsigned int cvtaddr = 0; unsigned int gpubaseaddr, hostbaseaddr, sizebytes; int i; if ((shmem->flags & GSL_FLAGS_INITIALIZED)) { for (i = 0; i < shmem->numapertures; i++) { hostbaseaddr = shmem->apertures[i].memarena->hostbaseaddr; gpubaseaddr = shmem->apertures[i].memarena->gpubaseaddr; sizebytes = shmem->apertures[i].memarena->sizebytes; // convert from gpu to host if (type == 0) { if (addr >= gpubaseaddr && addr < (gpubaseaddr + sizebytes)) { cvtaddr = hostbaseaddr + (addr - gpubaseaddr); break; } } // convert from host to gpu else if (type == 1) { if (addr >= hostbaseaddr && addr < (hostbaseaddr + sizebytes)) { cvtaddr = gpubaseaddr + (addr - hostbaseaddr); break; } } } } return (cvtaddr); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_cacheoperation(const gsl_memdesc_t *memdesc, unsigned int offsetbytes, unsigned int sizebytes, unsigned int operation) { int status = GSL_FAILURE; /* unreferenced formal parameter */ (void)memdesc; (void)offsetbytes; (void)sizebytes; (void)operation; /* do cache operation */ return (status); } //---------------------------------------------------------------------------- KGSL_API int kgsl_sharedmem_fromhostpointer(gsl_deviceid_t device_id, gsl_memdesc_t *memdesc, void* hostptr) { int status = GSL_FAILURE; memdesc->gpuaddr = (gpuaddr_t)hostptr; /* map physical address with hostptr */ memdesc->hostptr = hostptr; /* set virtual address also in memdesc */ /* unreferenced formal parameter */ (void)device_id; return (status); }