【关注我,后续持续新增专题博文,谢谢!!!】
上一篇我们讲了:
这一篇我们开始讲: 内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer
目录
一、背景
Camx HAL层ION Buffer可以分为两类:ImageBuffer和CmdBuffer。这篇博文就CmdBuffer模块进行分析介绍。
了解过高通Camx架构,一般知道bringup的开发并非都在kernel层,chi-cdk用户态也存在大量bringup开发工作,而用户态sensor等xml配置类似内核态dts配置一样,chi-cdk用户态存在大量sensor、马达等硬件bringup代码,需要讲xml配置通过CmdBuffer的方式下发到kernel去执行最终的驱动代码。
二、:CmdBufferManager管理单元
2.1:CmdBufferManager初始化
CmdBufferManager::Initialize是对CmdBufferManager进行初始化,可以看到核心代码只有一行:可以知道最终还是同ImageBuffer一样由CSLAlloc分配ION内存。
X:\bruce\SI\camx\src\core\camxcmdbuffermanager.cpp
CamxResult CmdBufferManager::Initialize(
const CHAR* pBufferManagerName,
const ResourceParams* pParams)
{
{
CAMX_ASSERT(NULL != pBufferManagerName);
OsUtils::StrLCpy(m_pBufferManagerName, pBufferManagerName, sizeof(m_pBufferManagerName));
m_params = *pParams;
result = InitializePool();
}
m_pLock = Mutex::Create("CmdBufferManager");
return result;
}
CamxResult CmdBufferManager::InitializePool()
{
CamxResult result = CamxResultSuccess;
CAMX_ASSERT((0 != m_params.resourceSize) && (0 == (m_params.poolSize % m_params.resourceSize)));
if ((0 == m_params.resourceSize) || (0 != (m_params.poolSize % m_params.resourceSize)))
{
result = CamxResultEInvalidArg;
}
else
{
SIZE_T allocationSize = 0;
UINT32 flags = m_params.memFlags;
m_numResources = m_params.poolSize / m_params.resourceSize;
CSLBufferInfo* pBufferInfo = static_cast<CSLBufferInfo*>(CAMX_CALLOC(sizeof(CSLBufferInfo)));
if (NULL == m_pParentBufferManager)
{
if (NULL != pBufferInfo)
{
result = CSLAlloc(m_pBufferManagerName,
pBufferInfo,
allocationSize,
m_params.alignment,
flags,
m_params.pDeviceIndices,
m_params.numDevices);
}
}
}
2.2:CmdBufferManager获取buffer
- CmdBufferManager获取buffer主要通过GetBuffer和GetBufferForRequest两个接口,返回都是PacketResource,它对应的就是CmdBuffer中CSLBufferInfo,本质就是xml的命令配置。
- CmdBufferManager是管理 CmdBuffer的,CmdBufferManager中有2条链表 m_busyPool和m_freePool,其中:m_freePool中存放着空闲的Buffer,m_busyPool中存放着正在被client 使用的Buffer。
CamxResult CmdBufferManager::GetBuffer(
PacketResource** ppBuffer)
{
LDLLNode* pNode = m_freePool.RemoveFromHead();
if (NULL != pNode)
{
*ppBuffer = static_cast<PacketResource*>(pNode->pData);
if (NULL == *ppBuffer)
{
result = CamxResultEInvalidState;
}
else
{
// Check canary
if (TRUE == (*ppBuffer)->GetUsageFlags().batchedPacket)
{
BatchedPacket* pBatchedPacket = static_cast<BatchedPacket*>(*ppBuffer);
pBatchedPacket->CheckCanary();
}
(*ppBuffer)->Reset();
(*ppBuffer)->SetRequestId(CamxInvalidRequestId);
}
CAMX_FREE(pNode);
}
m_pLock->Unlock();
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CmdBufferManager::GetBufferForRequest
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CmdBufferManager::GetBufferForRequest(
UINT64 requestId,
PacketResource** ppBuffer)
{
CamxResult result = GetBuffer(ppBuffer);
m_pLock->Lock();
if (CamxResultSuccess == result)
{
CAMX_ASSERT(NULL != *ppBuffer);
(*ppBuffer)->SetRequestId(requestId);
LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));
if (NULL != pNode)
{
pNode->pData = *ppBuffer;
m_busyPool.InsertToTail(pNode);
m_peakNumResourcesUsed = Utils::MaxUINT(m_peakNumResourcesUsed, m_busyPool.NumNodes());
}
else
{
result = CamxResultENoMemory;
}
}
m_pLock->Unlock();
return result;
}
三、:Camx CmdBuffer模块
3.1:CmdBuffer初始化
CmdBuffer初始化本质是对PacketResource进行初始化,再对CSLBufferInfo进行封装。
X:\bruce\SI\camx\src\core\camxcmdbuffer.cpp
CamxResult CmdBuffer::Initialize(
const CmdParams* pParams,
const CSLBufferInfo* pBufferInfo,
SIZE_T offset,
SIZE_T size)
{
if (NULL == pParams)
{
CAMX_LOG_ERROR(CamxLogGroupUtils, "Invalid input params");
return CamxResultEInvalidPointer;
}
CamxResult result = PacketResource::Initialize(pBufferInfo, offset, size);
return result;
}
CamxResult PacketResource::Initialize(
const CSLBufferInfo* pBufferInfo,
SIZE_T offset,
SIZE_T size)
{
CamxResult result = CamxResultSuccess;
if ((NULL == pBufferInfo) || (CSLInvalidHandle == pBufferInfo->hHandle))
{
result = CamxResultEInvalidArg;
CAMX_LOG_ERROR(CamxLogGroupUtils, "Invalid packet initialization args");
}
else
{
m_bufferInfo = *pBufferInfo;
m_offsetInBytes = offset;
m_sizeInBytes = size;
m_pUserdata = NULL;
m_requestId = CamxInvalidRequestId;
}
return result;
}
3.2 :CmdBuffer核心接口
CmdBuffer核心接口主要是这三个:
- CmdBuffer::BeginCommands:CSL开始准备下发命令到kernel
- CmdBuffer::CommitCommands:CSL正式提交命令到kernel
- CmdBuffer::CancelCommands:CSL取消下发命令到kernel
VOID* CmdBuffer::BeginCommands(
UINT32 numDwordsToReserve)
{
VOID* pDwords = NULL;
if ((GetNumDwordsAvailable() >= numDwordsToReserve) && (0 != numDwordsToReserve))
{
pDwords = GetCurrentWriteAddr();
m_pendingDwords = numDwordsToReserve;
// Put a canary to check in commit for overrun
// This requires that we allocate one extra dword for command buffers (in command buffer manager)
*static_cast<UINT*>(Utils::VoidPtrInc(pDwords, numDwordsToReserve * sizeof(UINT32))) = CamxCanary;
}
else
{
CAMX_LOG_ERROR(CamxLogGroupUtils, "Failed to reserve words-Dwords needed:%d, Dwords Available:%d",
numDwordsToReserve,
GetNumDwordsAvailable());
}
return pDwords;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CmdBuffer::CommitCommands
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CmdBuffer::CommitCommands()
{
CamxResult result = CamxResultSuccess;
CAMX_ASSERT_MESSAGE(GetNumDwordsAvailable() >= m_pendingDwords,
"Pending dwords: %d to commit is greater than available dwords: %d",
m_pendingDwords, GetNumDwordsAvailable());
if (0 >= m_pendingDwords)
{
CAMX_LOG_ERROR(CamxLogGroupUtils, "Invalid Command buffer state pending dwords: %d",
m_pendingDwords);
result = CamxResultEInvalidState;
}
else
{
// check for overrun
CAMX_ASSERT(CamxCanary == *static_cast<UINT*>(Utils::VoidPtrInc(GetCurrentWriteAddr(),
m_pendingDwords * sizeof(UINT32))));
m_resourceUsedDwords += m_pendingDwords;
m_pendingDwords = 0;
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// CmdBuffer::CancelCommands
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CamxResult CmdBuffer::CancelCommands()
{
CamxResult result = CamxResultSuccess;
m_pendingDwords = 0;
return result;
}
3.3 :CmdBuffer核心接口使用方式
下面就是OIS和马达bingup代码通过这些接口下发xml命令到kernel
camx/src/swl/sensor/camxois.cpp
result = m_pI2CInfoCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = m_pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = m_pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = m_pInitializeCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pCalibrateCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pOisModeCmdBuffer->CommitCommands(); in ConfigureOISMode()
camx/src/swl/sensor/camxactuator.cpp
result = pI2CInfoCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pPowerCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pInitializeCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pMoveFocusCmdBuffer->CommitCommands(); in MoveFocus()
camx/src/swl/sensor/camxactuator.cpp
CmdBuffer* pInitializeCmdBuffer = NULL; in CreateInitializePacket() local
pInitializeCmdBuffer = m_pParentNode->GetCmdBuffer(m_pInitializeCmdManager); in CreateInitializePacket()
(NULL == pInitializeCmdBuffer)) in CreateInitializePacket()
pInitializeCmdBuffer); in CreateInitializePacket()
pCmdBegin = pInitializeCmdBuffer->BeginCommands(initializeCmdSize / sizeof(UINT32)); in CreateInitializePacket()
result = pInitializeCmdBuffer->CommitCommands(); in CreateInitializePacket()
result = pPacket->AddCmdBufferReference(pInitializeCmdBuffer, NULL); in CreateInitializePacket()
m_pInitializeCmdManager->Recycle(pInitializeCmdBuffer); in CreateInitializePacket()
3.4 :CmdBuffer中sensor上电命令形式
以下就是imxxxx_sensor.xml配置的sensor上电的时序,最终会通过代码读取并封装到PacketResource打包成CmdBuffer,再下发大kernel。【camx chi bringup解析xml并下发kernel后面单独介绍,流程漫长】
<powerUpSequence>
<!--Power setting configuration
Contains: configType, configValue and delay in milli seconds -->
<powerSetting>
<!--Power configuration type
Supported types are: MCLK, VANA, VDIG, VIO, VAF, RESET, STANDBY -->
<configType>RESET</configType>
<!--Configuration value for the type of configuration -->
<configValue>0</configValue>
<!--Delay in milli seconds -->
<delayMs>1</delayMs>
</powerSetting>
<!--Power setting configuration
Contains: configType, configValue and delay in milli seconds -->
<powerSetting>
<configType>VANA</configType>
<configValue>0</configValue>
<delayMs>1</delayMs>
</powerSetting>
<powerSetting>
<configType>VDIG</configType>
<configValue>0</configValue>
<delayMs>1</delayMs>
</powerSetting>
<powerSetting>
<configType>VIO</configType>
<configValue>0</configValue>
<delayMs>0</delayMs>
</powerSetting>
<powerSetting>
<configType>MCLK</configType>
<configValue>24000000</configValue>
<delayMs>1</delayMs>
</powerSetting>
<powerSetting>
<configType>RESET</configType>
<configValue>1</configValue>
<delayMs>18</delayMs>
</powerSetting>
</powerUpSequence>
四、:总结
Camx CmdBufferManager和CmdBuffer之间的核心关系如上所述:CmdBufferManager通过GetBuffer的有2条链表 m_busyPool和m_freePool拿到CmdBuffer。
CmdBuffer核心接口主要是这三个:
- CmdBuffer::BeginCommands:CSL开始准备下发命令到kernel
- CmdBuffer::CommitCommands:CSL正式提交命令到kernel
- CmdBuffer::CancelCommands:CSL取消下发命令到kernel
【关注我,后续持续新增专题博文,谢谢!!!】
下一篇讲解: