Files
kernel_amazon_mt8127-common/arch/arm/mach-mt8127/camera_sysram.c
T
2019-04-21 09:20:06 +01:00

1479 lines
43 KiB
C

#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
//#include <asm/io.h>
#include <linux/proc_fs.h> //proc file use
#include <linux/slab.h> //kmalloc/kfree in kernel 3.10
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/xlog.h>
#include <mach/mt_reg_base.h>
#include <mach/mt_clkmgr.h>
#include <mach/sync_write.h>
#include <mach/camera_sysram.h>
#include <mach/mt_reg_base.h>
#include <mach/camera_sysram_imp.h>
#define ISP_VALID_REG_RANGE 0x10000
#define IMGSYS_BASE_ADDR 0x15000000
//-----------------------------------------------------------------------------
static SYSRAM_STRUCT Sysram;
//------------------------------------------------------------------------------
static void SYSRAM_GetTime(MUINT64* pUS64, MUINT32* pSec, MUINT32* pUSec)
{
ktime_t Time;
MUINT64 TimeSec;
//
Time = ktime_get();//ns
TimeSec = Time.tv64;
do_div( TimeSec, 1000 );
//
*pUS64 = TimeSec;
*pUSec = do_div( TimeSec, 1000000);
*pSec = (MUINT64)TimeSec;
}
//------------------------------------------------------------------------------
static void SYSRAM_CheckClock(void)
{
//LOG_MSG("AllocatedTbl(0x%08X),EnableClk(%d)",Sysram.AllocatedTbl,Sysram.EnableClk);
if(Sysram.AllocatedTbl)
{
if(!(Sysram.EnableClk))
{
Sysram.EnableClk = true;
/*
LOG_MSG("AllocatedTbl(0x%08lX),EnableClk(%d)",
Sysram.AllocatedTbl,
Sysram.EnableClk);
*/
}
}
else
{
if(Sysram.EnableClk)
{
Sysram.EnableClk = false;
/*
LOG_MSG("AllocatedTbl(0x%08lX),EnableClk(%d)",
Sysram.AllocatedTbl,
Sysram.EnableClk);
*/
}
}
}
//------------------------------------------------------------------------------
static void SYSRAM_DumpResMgr(void)
{
unsigned int u4Idx = 0;
LOG_MSG("TotalUserCount(%ld),AllocatedTbl(0x%lX)",
Sysram.TotalUserCount,
Sysram.AllocatedTbl);
//
for (u4Idx = 0; u4Idx < SYSRAM_USER_AMOUNT; u4Idx++)
{
if ( 0 < Sysram.AllocatedSize[u4Idx] )
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[u4Idx];
LOG_MSG("[id:%u][%s][size:0x%lX][pid:%d][tgid:%d][%s][%5lu.%06lu]",
u4Idx,
SysramUserName[u4Idx],
Sysram.AllocatedSize[u4Idx],
pUserInfo->pid,
pUserInfo->tgid,
pUserInfo->ProcName,
pUserInfo->TimeS,
pUserInfo->TimeUS);
}
}
LOG_MSG("End");
}
//------------------------------------------------------------------------------
static inline MBOOL SYSRAM_IsBadOwner(SYSRAM_USER_ENUM const User)
{
if(SYSRAM_USER_AMOUNT <= User || User < 0)
{
return MTRUE;
}
else
{
return MFALSE;
}
}
//------------------------------------------------------------------------------
static void SYSRAM_SetUserTaskInfo(SYSRAM_USER_ENUM const User)
{
if(!SYSRAM_IsBadOwner(User))
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[User];
//
pUserInfo->pid = current->pid;
pUserInfo->tgid = current->tgid;
memcpy(pUserInfo->ProcName, current->comm, sizeof(pUserInfo->ProcName));
//
SYSRAM_GetTime(&(pUserInfo->Time64), &(pUserInfo->TimeS), &(pUserInfo->TimeUS));
}
}
//------------------------------------------------------------------------------
static void SYSRAM_ResetUserTaskInfo(SYSRAM_USER_ENUM const User)
{
if(!SYSRAM_IsBadOwner(User))
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[User];
memset(pUserInfo, 0, sizeof(*pUserInfo));
}
}
//------------------------------------------------------------------------------
static inline void SYSRAM_SpinLock(void)
{
spin_lock(&Sysram.SpinLock);
}
//------------------------------------------------------------------------------
static inline void SYSRAM_SpinUnlock(void)
{
spin_unlock(&Sysram.SpinLock);
}
//------------------------------------------------------------------------------
static inline MBOOL SYSRAM_UserIsLocked(SYSRAM_USER_ENUM const User)
{
if((1 << User) & Sysram.AllocatedTbl)
{
return MTRUE;
}
else
{
return MFALSE;
}
}
//------------------------------------------------------------------------------
static inline MBOOL SYSRAM_UserIsUnlocked(SYSRAM_USER_ENUM const User)
{
if(SYSRAM_UserIsLocked(User) == 0)
{
return MTRUE;
}
else
{
return MFALSE;
}
}
//------------------------------------------------------------------------------
static void SYSRAM_LockUser(SYSRAM_USER_ENUM const User, MUINT32 const Size)
{
if(SYSRAM_UserIsLocked(User))
{
return;
}
//
Sysram.TotalUserCount++;
Sysram.AllocatedTbl |= (1 << User);
Sysram.AllocatedSize[User] = Size;
SYSRAM_SetUserTaskInfo(User);
//Debug Log.
if((1<<User) & SysramLogUserMask)
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[User];
LOG_MSG("[%s][%lu bytes]OK,Time(%lu.%06lu)",
SysramUserName[User],
Sysram.AllocatedSize[User],
pUserInfo->TimeS,
pUserInfo->TimeUS);
}
}
//------------------------------------------------------------------------------
static void SYSRAM_UnlockUser(SYSRAM_USER_ENUM const User)
{ if(SYSRAM_UserIsUnlocked(User))
{
return;
}
// Debug Log.
if((1<<User) & SysramLogUserMask)
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[User];
MUINT32 Sec, USec;
MUINT64 Time64 = 0;
SYSRAM_GetTime(&Time64,&Sec,&USec);
//
LOG_MSG("[%s][%lu bytes]Time(%lu.%06lu - %lu.%06lu)(%lu.%06lu)",
SysramUserName[User],
Sysram.AllocatedSize[User],
pUserInfo->TimeS,
pUserInfo->TimeUS,
Sec,
USec,
((MUINT32)(Time64-pUserInfo->Time64))/1000,
((MUINT32)(Time64-pUserInfo->Time64))%1000);
}
//
if(Sysram.TotalUserCount > 0)
{
Sysram.TotalUserCount--;
}
Sysram.AllocatedTbl &= (~(1 << User));
Sysram.AllocatedSize[User] = 0;
SYSRAM_ResetUserTaskInfo(User);
}
//------------------------------------------------------------------------------
static void SYSRAM_DumpLayout(void)
{
MUINT32 Index = 0;
SYSRAM_MEM_NODE_STRUCT* pCurrNode = NULL;
//
LOG_DMP("[SYSRAM_DumpLayout]\n");
LOG_DMP("AllocatedTbl = 0x%08lX\n",Sysram.AllocatedTbl);
LOG_DMP("=========================================\n");
for (Index = 0; Index < SYSRAM_MEM_BANK_AMOUNT; Index++)
{
LOG_DMP("\n [Mem Pool %ld] (IndexTbl, UserCount)=(%lX, %ld)\n",
Index,
SysramMemPoolInfo[Index].IndexTbl,
SysramMemPoolInfo[Index].UserCount);
LOG_DMP("[Locked Time] [Owner Offset Size Index pCurrent pPrevious pNext] [pid tgid] [Proc Name / Owner Name]\n");
pCurrNode = &SysramMemPoolInfo[Index].pMemNode[0];
while(NULL != pCurrNode)
{
SYSRAM_USER_ENUM const User = pCurrNode->User;
if(SYSRAM_IsBadOwner(User))
{
LOG_DMP(
"------------ --------"
" %2d\t0x%05lX 0x%05lX %ld %p %p\t%p\n",
pCurrNode->User,
pCurrNode->Offset,
pCurrNode->Length,
pCurrNode->Index,
pCurrNode,
pCurrNode->pPrev,
pCurrNode->pNext);
}
else
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[User];
LOG_DMP("%5lu.%06lu"
" %2d\t0x%05lX 0x%05lX %ld %p %p\t%p"
" %-4d %-4d \"%s\" / \"%s\"\n",
pUserInfo->TimeS,
pUserInfo->TimeUS,
User,
pCurrNode->Offset,
pCurrNode->Length,
pCurrNode->Index,
pCurrNode,
pCurrNode->pPrev,
pCurrNode->pNext,
pUserInfo->pid,
pUserInfo->tgid,
pUserInfo->ProcName,
SysramUserName[User]);
}
pCurrNode = pCurrNode->pNext;
};
}
LOG_DMP("\n");
SYSRAM_DumpResMgr();
}
//------------------------------------------------------------------------------
static SYSRAM_MEM_NODE_STRUCT* SYSRAM_AllocNode(SYSRAM_MEM_POOL_STRUCT*const pMemPoolInfo)
{
SYSRAM_MEM_NODE_STRUCT* pNode = NULL;
MUINT32 Index = 0;
//
for(Index = 0; Index < pMemPoolInfo->UserAmount; Index+=1)
{
if((pMemPoolInfo->IndexTbl) & (1 << Index))
{
pMemPoolInfo->IndexTbl &= (~(1 << Index));
// A free node is found.
pNode = &pMemPoolInfo->pMemNode[Index];
pNode->User = SYSRAM_USER_NONE;
pNode->Offset = 0;
pNode->Length = 0;
pNode->pPrev = NULL;
pNode->pNext = NULL;
pNode->Index = Index;
break;
}
}
// Shouldn't happen.
if( ! pNode )
{
LOG_ERR("returns NULL - pMemPoolInfo->IndexTbl(%lX)",pMemPoolInfo->IndexTbl);
}
return pNode;
}
//------------------------------------------------------------------------------
static void SYSRAM_FreeNode(
SYSRAM_MEM_POOL_STRUCT*const pMemPoolInfo,
SYSRAM_MEM_NODE_STRUCT*const pNode)
{
pMemPoolInfo->IndexTbl |= (1<<pNode->Index);
pNode->User = SYSRAM_USER_NONE;
pNode->Offset = 0;
pNode->Length = 0;
pNode->pPrev = NULL;
pNode->pNext = NULL;
pNode->Index = 0;
}
//------------------------------------------------------------------------------
static MBOOL SYSRAM_IsLegalSizeToAlloc(
SYSRAM_MEM_BANK_ENUM const MemBankNo,
SYSRAM_USER_ENUM const User,
MUINT32 const Size)
{
MUINT32 MaxSize = 0;
// (1) Check the memory pool.
switch(MemBankNo)
{
case SYSRAM_MEM_BANK_BAD:
case SYSRAM_MEM_BANK_AMOUNT:
{
// Illegal Memory Pool: return "illegal"
// Shouldn't happen.
goto EXIT;
}
default:
{
break;
}
}
// (2)
// Here we use the dynamic memory pools.
MaxSize = SysramUserSize[User];
//
EXIT:
if(MaxSize < Size)
{
LOG_ERR("[User:%s]requested size(0x%lX) > max size(0x%lX)",
SysramUserName[User],
Size,
MaxSize);
SYSRAM_DumpLayout();
return MFALSE;
}
return MTRUE;
}
//------------------------------------------------------------------------------
/*
Alignment should be 2^N, 4/8/2048 bytes alignment only
First fit algorithm
*/
static MUINT32 SYSRAM_AllocUserPhy(
SYSRAM_USER_ENUM const User,
MUINT32 const Size,
MUINT32 const Alignment,
SYSRAM_MEM_BANK_ENUM const MemBankNo
)
{
SYSRAM_MEM_NODE_STRUCT* pSplitNode = NULL;
SYSRAM_MEM_NODE_STRUCT* pCurrNode = NULL;
MUINT32 AlingnedAddr = 0;
MUINT32 ActualSize = 0;
//
SYSRAM_MEM_POOL_STRUCT*const pMemPoolInfo = SYSRAM_GetMemPoolInfo(MemBankNo);
if(!pMemPoolInfo)
{
return 0;
}
//
pCurrNode = &pMemPoolInfo->pMemNode[0];
for (; pCurrNode && pCurrNode->Offset < pMemPoolInfo->Size; pCurrNode = pCurrNode->pNext)
{
if(SYSRAM_USER_NONE == pCurrNode->User)
{
//Free space
AlingnedAddr = (pCurrNode->Offset + Alignment - 1)&(~(Alignment - 1));
ActualSize = Size + AlingnedAddr - pCurrNode->Offset;
if (ActualSize <= pCurrNode->Length)
{
// Hit!! Split into 2
// pSplitNode pointers to the next available (free) node.
pSplitNode = SYSRAM_AllocNode(pMemPoolInfo);
pSplitNode->Offset = pCurrNode->Offset + ActualSize;
pSplitNode->Length = pCurrNode->Length - ActualSize;
pSplitNode->pPrev = pCurrNode;
pSplitNode->pNext = pCurrNode->pNext;
//
pCurrNode->User = User;
pCurrNode->Length = ActualSize;
pCurrNode->pNext = pSplitNode;
//
if(NULL != pSplitNode->pNext)
{
pSplitNode->pNext->pPrev = pSplitNode;
}
//
pMemPoolInfo->UserCount++;
break;
}
//Not hit
ActualSize = 0;
}
};
//
return ActualSize ? (AlingnedAddr + pMemPoolInfo->Addr) : 0;
}
//------------------------------------------------------------------------------
static MBOOL SYSRAM_FreeUserPhy(
SYSRAM_USER_ENUM const User,
SYSRAM_MEM_BANK_ENUM const MemBankNo)
{
MBOOL Ret = MFALSE;
SYSRAM_MEM_NODE_STRUCT* pPrevOrNextNode = NULL;
SYSRAM_MEM_NODE_STRUCT* pCurrNode = NULL;
SYSRAM_MEM_NODE_STRUCT* pTempNode = NULL;
SYSRAM_MEM_POOL_STRUCT*const pMemPoolInfo = SYSRAM_GetMemPoolInfo(MemBankNo);
//
if(!pMemPoolInfo)
{
LOG_ERR("pMemPoolInfo==NULL,User(%d),MemBankNo(%d)",User,MemBankNo);
return MFALSE;
}
//
pCurrNode = &pMemPoolInfo->pMemNode[0];
for(; pCurrNode; pCurrNode = pCurrNode->pNext)
{
if(User == pCurrNode->User)
{
Ret = MTRUE; // user is found.
if ( pMemPoolInfo->UserCount > 0 )
pMemPoolInfo->UserCount--;
pCurrNode->User = SYSRAM_USER_NONE;
if(NULL != pCurrNode->pPrev)
{
pPrevOrNextNode = pCurrNode->pPrev;
//
if(SYSRAM_USER_NONE == pPrevOrNextNode->User)
{
//Merge previous: prev(o) + curr(x)
pTempNode = pCurrNode;
pCurrNode = pPrevOrNextNode;
pCurrNode->Length += pTempNode->Length;
pCurrNode->pNext = pTempNode->pNext;
if(NULL != pTempNode->pNext)
{
pTempNode->pNext->pPrev = pCurrNode;
}
SYSRAM_FreeNode(pMemPoolInfo, pTempNode);
}
}
if(NULL != pCurrNode->pNext)
{
pPrevOrNextNode = pCurrNode->pNext;
//
if(SYSRAM_USER_NONE == pPrevOrNextNode->User)
{
//Merge next: curr(o) + next(x)
pTempNode = pPrevOrNextNode;
pCurrNode->Length += pTempNode->Length;
pCurrNode->pNext = pTempNode->pNext;
if(NULL != pCurrNode->pNext)
{
pCurrNode->pNext->pPrev = pCurrNode;
}
SYSRAM_FreeNode(pMemPoolInfo, pTempNode);
}
}
break;
}
}
//
return Ret;
}
//------------------------------------------------------------------------------
static MUINT32 SYSRAM_AllocUser(
SYSRAM_USER_ENUM const User,
MUINT32 Size,
MUINT32 const Alignment)
{
MUINT32 Addr = 0;
SYSRAM_MEM_BANK_ENUM const MemBankNo = SYSRAM_GetMemBankNo(User);
//
if(SYSRAM_IsBadOwner(User))
{
LOG_ERR("User(%d) out of range(%d)",User,SYSRAM_USER_AMOUNT);
return 0;
}
//
if(!SYSRAM_IsLegalSizeToAlloc(MemBankNo, User, Size))
{
return 0;
}
//
switch (MemBankNo)
{
case SYSRAM_MEM_BANK_BAD:
case SYSRAM_MEM_BANK_AMOUNT:
{
// Do nothing.
break;
}
default:
{
Addr = SYSRAM_AllocUserPhy(
User,
Size,
Alignment,
MemBankNo);
break;
}
}
//
if(0 < Addr)
{
SYSRAM_LockUser(User,Size);
}
//
return Addr;
}
//------------------------------------------------------------------------------
static void SYSRAM_FreeUser(SYSRAM_USER_ENUM const User)
{
SYSRAM_MEM_BANK_ENUM const MemBankNo = SYSRAM_GetMemBankNo(User);
//
switch(MemBankNo)
{
case SYSRAM_MEM_BANK_BAD:
case SYSRAM_MEM_BANK_AMOUNT:
{
// Do nothing.
break;
}
default:
{
if(SYSRAM_FreeUserPhy(User, MemBankNo))
{
SYSRAM_UnlockUser(User);
}
else
{
LOG_ERR("Cannot free User(%d)",User);
SYSRAM_DumpLayout();
}
break;
}
}
}
//------------------------------------------------------------------------------
static MUINT32 SYSRAM_MsToJiffies(MUINT32 TimeMs)
{
return ((TimeMs*HZ + 512) >> 10);
}
//------------------------------------------------------------------------------
static MUINT32 SYSRAM_TryAllocUser(
SYSRAM_USER_ENUM const User,
MUINT32 const Size,
MUINT32 const Alignment)
{
MUINT32 Addr = 0;
//
SYSRAM_SpinLock();
//
if(SYSRAM_UserIsLocked(User))
{
SYSRAM_SpinUnlock();
LOG_ERR("[User:%s]has been already allocated!",SysramUserName[User]);
return 0;
}
//
Addr = SYSRAM_AllocUser(User, Size, Alignment);
if(Addr != 0)
{
SYSRAM_CheckClock();
}
SYSRAM_SpinUnlock();
//
return Addr;
}
//------------------------------------------------------------------------------
static MUINT32 SYSRAM_IOC_Alloc(
SYSRAM_USER_ENUM const User,
MUINT32 const Size,
MUINT32 Alignment,
MUINT32 const TimeoutMS)
{
MUINT32 Addr = 0;
INT32 TimeOut = 0;
//
if(SYSRAM_IsBadOwner(User))
{
LOG_ERR("User(%d) out of range(%d)",User,SYSRAM_USER_AMOUNT);
return 0;
}
//
if(0 == Size)
{
LOG_ERR("[User:%s]allocates 0 size!",SysramUserName[User]);
return 0;
}
//
Addr = SYSRAM_TryAllocUser(User, Size, Alignment);
if (
0 != Addr //success
|| 0 == TimeoutMS //failure without a timeout specified
)
{
goto EXIT;
}
//
TimeOut = wait_event_interruptible_timeout(
Sysram.WaitQueueHead,
0 != ( Addr = SYSRAM_TryAllocUser(User, Size, Alignment) ),
SYSRAM_MsToJiffies(TimeoutMS));
//
if(0 == TimeOut && 0 == Addr )
{
LOG_ERR("[User:%s]allocate timeout",SysramUserName[User]);
}
//
EXIT:
if (0 == Addr)
{ // Failure
LOG_ERR("[User:%s]fails to allocate.Size(%lu),Alignment(%lu),TimeoutMS(%lu)",
SysramUserName[User],
Size,
Alignment,
TimeoutMS);
SYSRAM_DumpLayout();
}
else
{ // Success
if ( (1<<User) & SysramLogUserMask )
{
LOG_MSG("[User:%s]%lu bytes OK",
SysramUserName[User],
Size);
}
}
//
return Addr;
}
//------------------------------------------------------------------------------
static void SYSRAM_IOC_Free(SYSRAM_USER_ENUM User)
{
if(SYSRAM_IsBadOwner(User))
{
LOG_ERR("User(%d) out of range(%d)",User,SYSRAM_USER_AMOUNT);
return;
}
//
SYSRAM_SpinLock();
SYSRAM_FreeUser(User);
wake_up_interruptible(&Sysram.WaitQueueHead);
SYSRAM_CheckClock();
SYSRAM_SpinUnlock();
//
if((1<<User) & SysramLogUserMask)
{
LOG_MSG("[User:%s]Done",SysramUserName[User]);
}
}
//------------------------------------------------------------------------------
static int SYSRAM_Open(
struct inode* pInode,
struct file* pFile)
{
int Ret = 0;
MUINT32 Sec = 0,USec = 0;
MUINT64 Time64 = 0;
SYSRAM_PROC_STRUCT* pProc;
//
SYSRAM_GetTime(&Time64, &Sec, &USec);
//
LOG_MSG("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
//
SYSRAM_SpinLock();
//
pFile->private_data = kmalloc(sizeof(SYSRAM_PROC_STRUCT) , GFP_ATOMIC);
if(pFile->private_data == NULL)
{
Ret = -ENOMEM;
}
else
{
pProc = (SYSRAM_PROC_STRUCT*)(pFile->private_data);
pProc->Pid = 0;
pProc->Tgid = 0;
strcpy(pProc->ProcName,SYSRAM_PROC_NAME);
pProc->Table = 0;
pProc->Time64 = Time64;
pProc->TimeS = Sec;
pProc->TimeUS = USec;
}
//
SYSRAM_SpinUnlock();
//
if(Ret == (-ENOMEM))
{
LOG_ERR("No enough memory");
/*
LOG_ERR("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
*/
}
//
return Ret;
}
//------------------------------------------------------------------------------
static int SYSRAM_Release(
struct inode* pInode,
struct file* pFile)
{
MUINT32 Index = 0;
MUINT32 Sec = 0,USec = 0;
MUINT64 Time64 = 0;
SYSRAM_PROC_STRUCT* pProc;
//
SYSRAM_GetTime(&Time64, &Sec, &USec);
//
LOG_MSG("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
//
if(pFile->private_data != NULL)
{
pProc = (SYSRAM_PROC_STRUCT*)(pFile->private_data);
//
if( pProc->Pid != 0 ||
pProc->Tgid != 0 ||
pProc->Table != 0)
{
//
LOG_WRN("Proc:Name(%s),pid(%d),tgid(%d),Table(0x%08lX),Time(%ld.%06ld)",
pProc->ProcName,
pProc->Pid,
pProc->Tgid,
pProc->Table,
pProc->TimeS,
pProc->TimeUS);
//
if(pProc->Table)
{
LOG_WRN("Force to release");
/*
LOG_WRN("Proc:Name(%s),pid(%d),tgid(%d),Table(0x%08lX),Time(%ld.%06ld)",
pProc->ProcName,
pProc->Pid,
pProc->Tgid,
pProc->Table,
pProc->TimeS,
pProc->TimeUS);
*/
SYSRAM_DumpLayout();
//
for(Index = 0 ; Index < SYSRAM_USER_AMOUNT; Index++)
{
if(pProc->Table & (1 << Index))
{
SYSRAM_IOC_Free((SYSRAM_USER_ENUM)Index);
}
}
}
}
//
kfree(pFile->private_data);
pFile->private_data = NULL;
}
else
{
LOG_WRN("private_data is NULL");
/*
LOG_WRN("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
*/
}
//
return 0;
}
//------------------------------------------------------------------------------
static int SYSRAM_Flush(
struct file* pFile,
fl_owner_t Id)
{
MUINT32 Index = 0;
MUINT32 Sec = 0,USec = 0;
MUINT64 Time64 = 0;
SYSRAM_PROC_STRUCT* pProc;
//
SYSRAM_GetTime(&Time64, &Sec, &USec);
//
LOG_MSG("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
//
if(pFile->private_data != NULL)
{
pProc = (SYSRAM_PROC_STRUCT *)pFile->private_data;
//
if( pProc->Pid != 0 ||
pProc->Tgid != 0 ||
pProc->Table != 0)
{
//
LOG_WRN("Proc:Name(%s),pid(%d),tgid(%d),Table(0x%08lX),Time(%ld.%06ld)",
pProc->ProcName,
pProc->Pid,
pProc->Tgid,
pProc->Table,
pProc->TimeS,
pProc->TimeUS);
//
if( pProc->Tgid == 0 &&
pProc->Table != 0)
{
LOG_ERR("No Tgid info");
/*
LOG_ERR("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
LOG_ERR("Proc:Name(%s),pid(%d),tgid(%d),Table(0x%08lX),Time(%ld.%06ld)",
pProc->ProcName,
pProc->Pid,
pProc->Tgid,
pProc->Table,
pProc->TimeS,
pProc->TimeUS);
*/
}
else
if( (pProc->Tgid == current->tgid) ||
((pProc->Tgid != current->tgid) && (strcmp(current->comm, "binder") == 0)))
{
if(pProc->Table)
{
LOG_WRN("Force to release");
/*
LOG_WRN("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
*/
SYSRAM_DumpLayout();
//
for(Index = 0 ; Index < SYSRAM_USER_AMOUNT; Index++)
{
if(pProc->Table & (1 << Index))
{
SYSRAM_IOC_Free((SYSRAM_USER_ENUM)Index);
}
}
//
pProc->Table= 0;
}
}
}
}
else
{
LOG_WRN("private_data is NULL");
/*
LOG_WRN("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
*/
}
//
return 0;
}
//------------------------------------------------------------------------------
static int SYSRAM_mmap(
struct file* pFile,
struct vm_area_struct* pVma)
{
//LOG_MSG("");
unsigned long length = 0;
MUINT32 pfn=0x0;
pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot);
length = pVma->vm_end - pVma->vm_start;
pfn=pVma->vm_pgoff<<PAGE_SHIFT;//page from number, physical address of kernel memory
LOG_WRN("pVma->vm_pgoff(0x%x),phy(0x%x),pVmapVma->vm_start(0x%x),pVma->vm_end(0x%x),length(0x%x)",\
pVma->vm_pgoff,pVma->vm_pgoff<<PAGE_SHIFT,pVma->vm_start,pVma->vm_end,length);
if((length>ISP_VALID_REG_RANGE) || (pfn<IMGSYS_BASE_ADDR) || (pfn>(IMGSYS_BASE_ADDR+ISP_VALID_REG_RANGE) || pVma->vm_end <= pVma->vm_start))
{
LOG_ERR("mmap range error : vm_start(0x%x),vm_end(0x%x),length(0x%x),pfn(0x%x)!",pVma->vm_start,pVma->vm_end,length,pfn);
return -EAGAIN;
}
if(remap_pfn_range(
pVma,
pVma->vm_start,
pVma->vm_pgoff,
pVma->vm_end - pVma->vm_start,
pVma->vm_page_prot))
{
LOG_ERR("fail");
return -EAGAIN;
}
return 0;
}
//------------------------------------------------------------------------------
static long SYSRAM_Ioctl(
struct file* pFile,
unsigned int Cmd,
unsigned long Param)
{
MINT32 Ret = 0;
MUINT32 Sec = 0,USec = 0;
MUINT64 Time64 = 0;
SYSRAM_PROC_STRUCT* pProc = (SYSRAM_PROC_STRUCT*)pFile->private_data;
SYSRAM_ALLOC_STRUCT Alloc;
SYSRAM_USER_ENUM User;
//
SYSRAM_GetTime(&Time64, &Sec, &USec);
/*
LOG_MSG("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
*/
if(pFile->private_data == NULL)
{
LOG_WRN("private_data is NULL.");
Ret = -EFAULT;
goto EXIT;
}
//
switch(Cmd)
{
case SYSRAM_ALLOC:
{
if(copy_from_user(&Alloc, (void*)Param, sizeof(SYSRAM_ALLOC_STRUCT)) == 0)
{
if(SYSRAM_IsBadOwner(Alloc.User))
{
LOG_ERR("User(%d) out of range(%d)",Alloc.User,SYSRAM_USER_AMOUNT);
Ret = -EFAULT;
goto EXIT;
}
//
Alloc.Addr = SYSRAM_IOC_Alloc(
Alloc.User,
Alloc.Size,
Alloc.Alignment,
Alloc.TimeoutMS);
if(Alloc.Addr != 0)
{
SYSRAM_SpinLock();
pProc->Table |= (1 << Alloc.User);
if(pProc->Tgid == 0)
{
pProc->Pid = current->pid;
pProc->Tgid = current->tgid;
strcpy(pProc->ProcName,current->comm);
SYSRAM_SpinUnlock();
}
else
{
SYSRAM_SpinUnlock();
if(pProc->Tgid != current->tgid)
{
LOG_ERR("Tgid is inconsistent");
Ret = -EFAULT;
}
}
}
else
{
Ret = -EFAULT;
}
//
if(copy_to_user((void*)Param, &Alloc, sizeof(SYSRAM_ALLOC_STRUCT)) )
{
LOG_ERR("copy to user failed");
Ret = -EFAULT;
}
}
else
{
LOG_ERR("copy_from_user fail");
Ret = -EFAULT;
}
break;
}
//
case SYSRAM_FREE:
{
if(copy_from_user(&User, (void*)Param, sizeof(SYSRAM_USER_ENUM)) == 0)
{
if(SYSRAM_IsBadOwner(User))
{
LOG_ERR("User(%d) out of range(%d)",User,SYSRAM_USER_AMOUNT);
Ret = -EFAULT;
goto EXIT;
}
//
SYSRAM_SpinLock();
if((pProc->Table) & (1 << User))
{
SYSRAM_SpinUnlock();
SYSRAM_IOC_Free(User);
SYSRAM_SpinLock();
//
pProc->Table &= (~(1 << User));
if(pProc->Table == 0)
{
pProc->Pid = 0;
pProc->Tgid = 0;
strcpy(pProc->ProcName,SYSRAM_PROC_NAME);
}
SYSRAM_SpinUnlock();
}
else
{
SYSRAM_SpinUnlock();
LOG_WRN("Freeing unallocated buffer user(%d)",User);
Ret = -EFAULT;
}
}
else
{
LOG_ERR("copy_from_user fail");
Ret = -EFAULT;
}
break;
}
case SYSRAM_DUMP:
{
SYSRAM_DumpLayout();
break;
}
default:
{
LOG_WRN("No such command");
Ret = -EINVAL;
break;
}
}
//
EXIT:
if(Ret != 0)
{
LOG_ERR("Fail");
LOG_ERR("Cur:Name(%s),pid(%d),tgid(%d),Time(%ld.%06ld)",
current->comm,
current->pid,
current->tgid,
Sec,
USec);
if(pFile->private_data != NULL)
{
LOG_ERR("Proc:Name(%s),pid(%d),tgid(%d),Table(0x%08lX),Time(%ld.%06ld)",
pProc->ProcName,
pProc->Pid,
pProc->Tgid,
pProc->Table,
Sec,
USec);
}
}
//
return Ret;
}
//------------------------------------------------------------------------------
static const struct file_operations SysramFileOper =
{
.owner = THIS_MODULE,
.open = SYSRAM_Open,
.release = SYSRAM_Release,
.flush = SYSRAM_Flush,
.unlocked_ioctl = SYSRAM_Ioctl,
.mmap = SYSRAM_mmap,
};
//------------------------------------------------------------------------------
static inline int SYSRAM_RegCharDrv(void)
{
LOG_MSG("E");
if(alloc_chrdev_region(&Sysram.DevNo, 0, 1,SYSRAM_DEV_NAME) )
{
LOG_ERR("allocate device no failed");
return -EAGAIN;
}
//allocate driver
Sysram.pCharDrv = cdev_alloc();
if(Sysram.pCharDrv == NULL)
{
unregister_chrdev_region(Sysram.DevNo, 1);
LOG_ERR("allocate mem for kobject failed");
return -ENOMEM;
}
//Attatch file operation.
cdev_init(Sysram.pCharDrv, &SysramFileOper);
Sysram.pCharDrv->owner = THIS_MODULE;
//Add to system
if(cdev_add(Sysram.pCharDrv, Sysram.DevNo, 1))
{
LOG_ERR("Attatch file operation failed");
unregister_chrdev_region(Sysram.DevNo, 1);
return -EAGAIN;
}
LOG_MSG("X");
return 0;
}
//------------------------------------------------------------------------------
static inline void SYSRAM_UnregCharDrv(void)
{
LOG_MSG("E");
//Release char driver
cdev_del(Sysram.pCharDrv);
unregister_chrdev_region(Sysram.DevNo, 1);
LOG_MSG("X");
}
//------------------------------------------------------------------------------
static int SYSRAM_Probe(struct platform_device *pDev)
{
MINT32 Ret = 0;
MUINT32 Index = 0;
struct device* sysram_device = NULL;
//
LOG_MSG("E");
//register char driver
//allocate major no
if(SYSRAM_RegCharDrv())
{
LOG_ERR("register char failed");
return -EAGAIN;
}
Sysram.pClass = class_create(THIS_MODULE, "SysramDrv");
if(IS_ERR(Sysram.pClass))
{
Ret = PTR_ERR(Sysram.pClass);
LOG_ERR("Unable to create class, err(%ld)", Ret);
return Ret;
}
sysram_device = device_create(
Sysram.pClass,
NULL,
Sysram.DevNo,
NULL,
SYSRAM_DEV_NAME);
//Initialize variables
spin_lock_init(&Sysram.SpinLock);
Sysram.TotalUserCount = 0;
Sysram.AllocatedTbl = 0;
memset(Sysram.AllocatedSize, 0, sizeof(Sysram.AllocatedSize));
memset(Sysram.UserInfo, 0, sizeof(Sysram.UserInfo));
init_waitqueue_head(&Sysram.WaitQueueHead);
Sysram.EnableClk = MFALSE;
//
for(Index = 0; Index < SYSRAM_MEM_BANK_AMOUNT; Index++)
{
SysramMemPoolInfo[Index].pMemNode[0].User = SYSRAM_USER_NONE;
SysramMemPoolInfo[Index].pMemNode[0].Offset = 0;
SysramMemPoolInfo[Index].pMemNode[0].Length = SysramMemPoolInfo[Index].Size;
SysramMemPoolInfo[Index].pMemNode[0].Index = 0;
SysramMemPoolInfo[Index].pMemNode[0].pNext = NULL;
SysramMemPoolInfo[Index].pMemNode[0].pPrev = NULL;
SysramMemPoolInfo[Index].IndexTbl = (~0x1);
SysramMemPoolInfo[Index].UserCount= 0;
}
//
for(Index = 0; Index < SYSRAM_USER_AMOUNT; Index++)
{
Sysram.AllocatedSize[Index] = 0;
}
Sysram.DebugFlag = SYSRAM_DEBUG_DEFAULT;
//
LOG_MSG("X");
return Ret;
}
//------------------------------------------------------------------------------
static int SYSRAM_Remove(struct platform_device *pDev)
{
LOG_MSG("E");
//unregister char driver.
SYSRAM_UnregCharDrv();
//
device_destroy(Sysram.pClass, Sysram.DevNo);
class_destroy(Sysram.pClass);
//
LOG_MSG("X");
//
return 0;
}
//------------------------------------------------------------------------------
static int SYSRAM_Suspend(
struct platform_device* pDev,
pm_message_t Mesg)
{
LOG_MSG("");
return 0;
}
//------------------------------------------------------------------------------
static int SYSRAM_Resume(struct platform_device *pDev)
{
LOG_MSG("");
return 0;
}
//------------------------------------------------------------------------------
static struct platform_driver SysramPlatformDriver =
{
.probe = SYSRAM_Probe,
.remove = SYSRAM_Remove,
.suspend = SYSRAM_Suspend,
.resume = SYSRAM_Resume,
.driver =
{
.name = SYSRAM_DEV_NAME,
.owner = THIS_MODULE,
}
};
//------------------------------------------------------------------------------
static int SYSRAM_DumpLayoutToProc(
struct file *pFile,
char *pStart,
size_t Off,
loff_t *Count)
{
MINT32 Length = 0;
MUINT32 Index = 0;
SYSRAM_MEM_NODE_STRUCT* pCurrNode = NULL;
char *buffer_log = kmalloc(1000*sizeof(unsigned int), GFP_KERNEL);
if (buffer_log == NULL) {
LOG_ERR("kmalloc fail");
kfree(buffer_log);
return -EFAULT;
}
if (*Count > 0) {
kfree(buffer_log);
return 0;
}
Length += sprintf(buffer_log, "\n[SYSRAM_DumpLayoutToProc]\n");
Length += sprintf(buffer_log + Length, "AllocatedTbl = 0x%08lX\n",Sysram.AllocatedTbl);
Length += sprintf(buffer_log + Length, "=========================================\n" );
for (Index = 0; Index < SYSRAM_MEM_BANK_AMOUNT; Index++)
{
Length += sprintf(buffer_log + Length, "\n [Mem Pool %ld] (IndexTbl, UserCount)=(%lX, %ld)\n",
Index,
SysramMemPoolInfo[Index].IndexTbl,
SysramMemPoolInfo[Index].UserCount);
Length += sprintf(buffer_log + Length, "[Locked Time] [Owner Offset Size Index pCurrent pPrevious pNext] [pid tgid] [Proc Name / Owner Name]\n");
pCurrNode = &SysramMemPoolInfo[Index].pMemNode[0];
while ( NULL != pCurrNode )
{
SYSRAM_USER_ENUM const User = pCurrNode->User;
if ( SYSRAM_IsBadOwner(User) )
{
Length += sprintf(buffer_log + Length,
"------------ --------"
" %2d\t0x%05lX 0x%05lX %ld %p %p\t%p\n",
pCurrNode->User,
pCurrNode->Offset,
pCurrNode->Length,
pCurrNode->Index,
pCurrNode,
pCurrNode->pPrev,
pCurrNode->pNext
);
}
else
{
SYSRAM_USER_STRUCT*const pUserInfo = &Sysram.UserInfo[User];
Length += sprintf(buffer_log + Length,
"%5lu.%06lu"
" %2d\t0x%05lX 0x%05lX %ld %p %p\t%p"
" %-4d %-4d \"%s\" / \"%s\"\n",
pUserInfo->TimeS,
pUserInfo->TimeUS,
User,
pCurrNode->Offset,
pCurrNode->Length,
pCurrNode->Index,
pCurrNode,
pCurrNode->pPrev,
pCurrNode->pNext,
pUserInfo->pid,
pUserInfo->tgid,
pUserInfo->ProcName,
SysramUserName[User]);
}
pCurrNode = pCurrNode->pNext;
};
}
if (copy_to_user(pStart, buffer_log, Length)) {
LOG_ERR("copy_to_user fail");
kfree(buffer_log);
return -EFAULT;
}
*Count = *Count + Length;
kfree(buffer_log);
return Length;
}
//------------------------------------------------------------------------------
static int SYSRAM_ReadFlag(
struct file *pFile,
char *pStart,
size_t Off,
loff_t *Count)
{
MINT32 Length = 0;
char *buffer_log = kmalloc(1000*sizeof(unsigned int), GFP_KERNEL);
if (buffer_log == NULL) {
LOG_ERR("kmalloc fail");
kfree(buffer_log);
return -EFAULT;
}
if (*Count > 0) {
kfree(buffer_log);
return 0;
}
Length += sprintf(buffer_log, "\r\n[SYSRAM_ReadFlag]\r\n");
Length += sprintf(buffer_log + Length, "Sysram.DebugFlag = 0x%08lX\r\n",Sysram.DebugFlag);
if (copy_to_user(pStart, buffer_log, Length)) {
LOG_ERR("copy_to_user fail");
kfree(buffer_log);
return -EFAULT;
}
*Count = *Count + Length;
kfree(buffer_log);
return Length;
}
//------------------------------------------------------------------------------
static int SYSRAM_WriteFlag(
struct file* pFile,
const char* pBuffer,
unsigned long Count,
void* pData)
{
char acBuf[32];
MUINT32 u4CopySize = 0;
MUINT32 u4SysramDbgFlag = 0;
//
u4CopySize = (Count < (sizeof(acBuf) - 1)) ? Count : (sizeof(acBuf) - 1);
if(copy_from_user(acBuf, pBuffer, u4CopySize))
{
return 0;
}
acBuf[u4CopySize] = '\0';
if(3 == sscanf(acBuf, "%lx", &u4SysramDbgFlag))
{
Sysram.DebugFlag = u4SysramDbgFlag;
}
return Count;
}
/*******************************************************************************
*
********************************************************************************/
static const struct file_operations fsysram_proc_fops = {
.read = SYSRAM_DumpLayoutToProc,
.write = NULL,
};
static const struct file_operations fsysram_flag_proc_fops = {
.read = SYSRAM_ReadFlag,
.write = SYSRAM_WriteFlag,
};
//-----------------------------------------------------------------------------
static int __init SYSRAM_Init(void)
{
struct proc_dir_entry *pEntry;
//
LOG_MSG("E");
//
if(platform_driver_register(&SysramPlatformDriver))
{
LOG_ERR("failed to register sysram driver");
return -ENODEV;
}
//
//linux-3.10 procfs API changed
#if 1
proc_create("sysram",0,NULL,&fsysram_proc_fops);
proc_create("sysram_flag",0,NULL,&fsysram_flag_proc_fops);
#else
pEntry = create_proc_entry("sysram", 0, NULL);
if(pEntry)
{
pEntry->read_proc = SYSRAM_DumpLayoutToProc;
pEntry->write_proc = NULL;
}
else
{
LOG_ERR("add /proc/sysram entry fail.");
}
//
pEntry = create_proc_entry("sysram_flag", 0, NULL);
if(pEntry)
{
pEntry->read_proc = SYSRAM_ReadFlag;
pEntry->write_proc = SYSRAM_WriteFlag;
}
else
{
LOG_ERR("add /proc/sysram_flag entry fail");
}
#endif
LOG_MSG("X");
//
return 0;
}
//------------------------------------------------------------------------------
static void __exit SYSRAM_Exit(void)
{
LOG_MSG("E");
platform_driver_unregister(&SysramPlatformDriver);
LOG_MSG("X");
}
//------------------------------------------------------------------------------
module_init(SYSRAM_Init);
module_exit(SYSRAM_Exit);
MODULE_DESCRIPTION("Camera sysram driver");
MODULE_AUTHOR("Marx <marx.chiu@mediatek.com>");
MODULE_LICENSE("GPL");
//------------------------------------------------------------------------------