blob: f1ea4940ca67c2e057fa1ce7121a88162b079036 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) Marvell International Ltd. and its affiliates
*
* Marvell GPL License Option
*
* If you received this File from Marvell, you may opt to use, redistribute and/or
* modify this File in accordance with the terms and conditions of the General
* Public License Version 2, June 1991 (the "GPL License"), a copy of which is
* available along with the File in the license.txt file or by writing to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
* on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
* WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
* DISCLAIMED. The GPL License provides additional details about this warranty
* disclaimer.
********************************************************************************/
/*******************************************************************************
System head files
*/
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/vmalloc.h>
#include <linux/kdev_t.h>
#include <asm/page.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/version.h>
/*******************************************************************************
Local head files
*/
#include "shm_type.h"
#include "shm_device.h"
#include "shm_api.h"
/*******************************************************************************
Module Variable
*/
MV_SHM_BaseInfo_t MV_SHM_CACHE_BASEINFO_DATA = { 0, 0, 0, 0, -1 };
MV_SHM_BaseInfo_t MV_SHM_NONCACHE_BASEINFO_DATA = { 0, 0, 0, 0, -1 };
shm_device_t *shm_api_device_cache = NULL;
shm_device_t *shm_api_device_noncache = NULL;
static unsigned long MV_SHM_ioremap(unsigned long phys_start, unsigned long size)
{
struct vm_struct *area;
area = get_vm_area(size, VM_IOREMAP);
if (area == NULL)
return ((uint) NULL);
if (ioremap_page_range((unsigned long)area->addr,
(unsigned long)area->addr + size, phys_start, PAGE_KERNEL)) {
return ((uint) NULL);
}
return area->addr;
}
/*******************************************************************************
Module API: for kernel module use only, mainly CBuf and Graphics driver, suppose to be removed later
*/
//the device should be match with ioremap cachablity
//we still need to map both cache and non-cache device, since kernel(driver) will use the addr convert
int MV_SHM_Init(shm_device_t * device_noncache, shm_device_t * device_cache)
{
int res;
if (device_noncache == NULL || device_cache == NULL)
return -EINVAL;
shm_api_device_noncache = device_noncache;
/* prepare MV_SHM_BASEINFO_DATA */
res = shm_device_get_baseinfo(shm_api_device_noncache,
&MV_SHM_NONCACHE_BASEINFO_DATA);
if (res != 0) {
shm_error("shm_device_get_baseinfo failed. (%d)", res);
goto err_exit1;
}
MV_SHM_NONCACHE_BASEINFO_DATA.m_size = device_noncache->m_size;
/* map phyiscal address to kernel virtual address */
shm_trace("memory ioremap_noncache, base:0x%08X, size:0x%08X\n",
MV_SHM_NONCACHE_BASEINFO_DATA.m_base_physaddr,
MV_SHM_NONCACHE_BASEINFO_DATA.m_size);
MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr =
(uint)
ioremap_nocache(MV_SHM_NONCACHE_BASEINFO_DATA.m_base_physaddr,
MV_SHM_NONCACHE_BASEINFO_DATA.m_size);
if (MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr == (uint) NULL) {
shm_error("ioremap_nocache failed.");
res = -ENOMEM;
goto err_exit1;
}
device_noncache->m_engine->m_cache_or_noncache = SHM_NONCACHE;
device_noncache->m_engine->m_virt_base =
MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr;
/////////////////////map cache device in kernel space//////////////////////////
shm_api_device_cache = device_cache;
/* prepare MV_SHM_BASEINFO_DATA */
res = shm_device_get_baseinfo(shm_api_device_cache,
&MV_SHM_CACHE_BASEINFO_DATA);
if (res != 0) {
shm_error("shm_device_get_baseinfo failed. (%d)", res);
goto err_exit1;
}
MV_SHM_CACHE_BASEINFO_DATA.m_size = device_cache->m_size;
/* map phyiscal address to kernel virtual address */
shm_trace("memory ioremap, base:0x%08X, size:0x%08X\n",
MV_SHM_CACHE_BASEINFO_DATA.m_base_physaddr,
MV_SHM_CACHE_BASEINFO_DATA.m_size);
MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr =
(uint)MV_SHM_ioremap(MV_SHM_CACHE_BASEINFO_DATA.m_base_physaddr,
MV_SHM_CACHE_BASEINFO_DATA.m_size);
if (MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr == (uint) NULL) {
shm_error("ioremap failed.");
res = -ENOMEM;
goto err_exit2;
}
device_cache->m_engine->m_cache_or_noncache = SHM_CACHE;
device_cache->m_engine->m_virt_base =
MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr;
shm_trace("memory base virt addr (cache) = 0x%08X\n",
MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr);
shm_trace("memory base virt addr (non-cache) = 0x%08X\n",
MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr);
shm_trace("MV_SHM_Init OK\n");
return 0;
err_exit2:
// unmap kernel virtual address
iounmap((void *)(MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr));
err_exit1:
shm_api_device_noncache = shm_api_device_cache = NULL;
shm_error("MV_SHM_Init failed !!!\n");
return res;
}
int MV_SHM_Exit(void)
{
if (shm_api_device_noncache == NULL || shm_api_device_cache == NULL)
return -EINVAL;
/* unmap kernel virtual address */
iounmap((void *)(MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr));
iounmap((void *)(MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr));
shm_api_device_noncache = shm_api_device_cache = NULL;
shm_trace("MV_SHM_Exit OK\n");
return 0;
}
#if 1 //no one should use this api!!!
int MV_SHM_GetCacheMemInfo(pMV_SHM_MemInfo_t pInfo)
{
if (pInfo == NULL)
return -EINVAL;
if (shm_api_device_cache == NULL)
return -ENODEV;
return shm_device_get_meminfo(shm_api_device_cache, pInfo);
}
#endif
int MV_SHM_GetCacheBaseInfo(pMV_SHM_BaseInfo_t pInfo)
{
if (pInfo == NULL)
return -EINVAL;
if (shm_api_device_cache == NULL)
return -ENODEV;
memcpy(pInfo, &MV_SHM_CACHE_BASEINFO_DATA,
sizeof(MV_SHM_CACHE_BASEINFO_DATA));
return 0;
}
//these malloc are for cache, now in kernel space we have separate api just as user space did
size_t MV_SHM_Malloc(size_t Size, size_t Alignment)
{
size_t Offset;
if ((shm_api_device_cache == NULL) || (Size == 0) || (Alignment % 2))
return ERROR_SHM_MALLOC_FAILED;
if (shm_check_alignment(Alignment) != 0)
return ERROR_SHM_MALLOC_FAILED;
shm_round_size(Size);
shm_round_alignment(Alignment);
Offset = shm_device_allocate(shm_api_device_cache, Size, Alignment);
return Offset;
}
int MV_SHM_Takeover(size_t Offset)
{
if (NULL == shm_api_device_cache)
return -ENODEV;
return shm_device_takeover(shm_api_device_cache, Offset);
}
int MV_SHM_Giveup(size_t Offset)
{
if (NULL == shm_api_device_cache)
return -ENODEV;
return shm_device_giveup(shm_api_device_cache, Offset);
}
int MV_SHM_Free(size_t Offset)
{
if (shm_api_device_cache == NULL)
return -ENODEV;
return shm_device_free(shm_api_device_cache, Offset);
}
//these malloc are for non-cache
size_t MV_SHM_NONCACHE_Malloc(size_t Size, size_t Alignment)
{
size_t Offset;
if ((shm_api_device_noncache == NULL) || (Size == 0) || (Alignment % 2))
return ERROR_SHM_MALLOC_FAILED;
if (shm_check_alignment(Alignment) != 0)
return ERROR_SHM_MALLOC_FAILED;
shm_round_size(Size);
shm_round_alignment(Alignment);
Offset = shm_device_allocate(shm_api_device_noncache, Size, Alignment);
return Offset;
}
int MV_SHM_NONCACHE_Free(size_t Offset)
{
if (shm_api_device_noncache == NULL)
return -ENODEV;
return shm_device_free(shm_api_device_noncache, Offset);
}
void *MV_SHM_GetNonCacheVirtAddr(size_t Offset)
{
if ((shm_api_device_noncache == NULL)
|| (Offset >= MV_SHM_NONCACHE_BASEINFO_DATA.m_size))
return NULL;
return (void *)(Offset + MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr);
}
void *MV_SHM_GetCacheVirtAddr(size_t Offset)
{
if ((shm_api_device_cache == NULL)
|| (Offset >= MV_SHM_CACHE_BASEINFO_DATA.m_size))
return NULL;
return (void *)(Offset + MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr);
}
void *MV_SHM_GetNonCachePhysAddr(size_t Offset)
{
if ((shm_api_device_noncache == NULL)
|| (Offset >= MV_SHM_NONCACHE_BASEINFO_DATA.m_size))
return NULL;
return (void *)(Offset + MV_SHM_NONCACHE_BASEINFO_DATA.m_base_physaddr);
}
void *MV_SHM_GetCachePhysAddr(size_t Offset)
{
if ((shm_api_device_cache == NULL)
|| (Offset >= MV_SHM_CACHE_BASEINFO_DATA.m_size))
return NULL;
return (void *)(Offset + MV_SHM_CACHE_BASEINFO_DATA.m_base_physaddr);
}
size_t MV_SHM_RevertNonCacheVirtAddr(void *ptr)
{
if (shm_api_device_noncache == NULL)
return ERROR_SHM_MALLOC_FAILED;
if (((size_t) ptr < MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr) ||
((size_t) ptr >=
MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr +
MV_SHM_NONCACHE_BASEINFO_DATA.m_size))
return ERROR_SHM_MALLOC_FAILED;
return ((size_t) ptr - MV_SHM_NONCACHE_BASEINFO_DATA.m_base_virtaddr);
}
size_t MV_SHM_RevertCacheVirtAddr(void *ptr)
{
if (shm_api_device_cache == NULL)
return ERROR_SHM_MALLOC_FAILED;
if (((size_t) ptr < MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr) ||
((size_t) ptr >=
MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr +
MV_SHM_CACHE_BASEINFO_DATA.m_size))
return ERROR_SHM_MALLOC_FAILED;
return ((size_t) ptr - MV_SHM_CACHE_BASEINFO_DATA.m_base_virtaddr);
}
size_t MV_SHM_RevertNonCachePhysAddr(void *ptr)
{
if (shm_api_device_noncache == NULL)
return ERROR_SHM_MALLOC_FAILED;
if (((size_t) ptr < MV_SHM_NONCACHE_BASEINFO_DATA.m_base_physaddr) ||
((size_t) ptr >=
MV_SHM_NONCACHE_BASEINFO_DATA.m_base_physaddr +
MV_SHM_NONCACHE_BASEINFO_DATA.m_size))
return ERROR_SHM_MALLOC_FAILED;
return ((size_t) ptr - MV_SHM_NONCACHE_BASEINFO_DATA.m_base_physaddr);
}
size_t MV_SHM_RevertCachePhysAddr(void *ptr)
{
if (shm_api_device_cache == NULL)
return ERROR_SHM_MALLOC_FAILED;
if (((size_t) ptr < MV_SHM_CACHE_BASEINFO_DATA.m_base_physaddr) ||
((size_t) ptr >=
MV_SHM_CACHE_BASEINFO_DATA.m_base_physaddr +
MV_SHM_CACHE_BASEINFO_DATA.m_size))
return ERROR_SHM_MALLOC_FAILED;
return ((size_t) ptr - MV_SHM_CACHE_BASEINFO_DATA.m_base_physaddr);
}
EXPORT_SYMBOL(MV_SHM_Malloc);
EXPORT_SYMBOL(MV_SHM_Free);
EXPORT_SYMBOL(MV_SHM_Takeover);
EXPORT_SYMBOL(MV_SHM_Giveup);
EXPORT_SYMBOL(MV_SHM_NONCACHE_Malloc);
EXPORT_SYMBOL(MV_SHM_NONCACHE_Free);
EXPORT_SYMBOL(MV_SHM_GetNonCacheVirtAddr);
EXPORT_SYMBOL(MV_SHM_GetCacheVirtAddr);
EXPORT_SYMBOL(MV_SHM_GetNonCachePhysAddr);
EXPORT_SYMBOL(MV_SHM_GetCachePhysAddr);
EXPORT_SYMBOL(MV_SHM_RevertNonCacheVirtAddr);
EXPORT_SYMBOL(MV_SHM_RevertCacheVirtAddr);
EXPORT_SYMBOL(MV_SHM_RevertNonCachePhysAddr);
EXPORT_SYMBOL(MV_SHM_RevertCachePhysAddr);
EXPORT_SYMBOL(MV_SHM_GetCacheMemInfo);
EXPORT_SYMBOL(MV_SHM_GetCacheBaseInfo);