blob: 3aa4c6dea66c28ae44e241a5a51afa084c333f67 [file] [log] [blame]
/*
* \file optimus_buffer_manager.c
* \brief buffer manager for download data: A thin layer between receiving partition data and writing flash
*
* \version 1.0.0
* \date 2013/5/2
* \author Sam.Wu <yihui.wu@Amlogic.com>
*
* Copyright (c) 2013 Amlogic Inc.. All Rights Reserved.
*
*/
#include "../v2_burning_i.h"
#define OPTIMUS_SLOT_STA_FREE (0)//buffer slot not used yet
#define OPTIMUS_SLOT_STA_USED (0xee)//buffer slot current used for download
#define OPTIMUS_SLOT_STA_LEFT (0xdd)//buffer slot not disposed over
#define PKT_TRANSFER_STA_EMPTY 0
#define PKT_TRANSFER_STA_WORKING 1
#define PKT_TRANSFER_STA_END 2
typedef struct bufManager{
const u8* transferBuf;//transfer buffer address
const u32 transferBufSz;//transfer buffer size to
const u32 transferUnitSz;//64k
u32 writeBackUnitSz;//for NAND is transferSz, for sparse is transferUnitSz
u64 tplcmdTotalSz;//total size of a file-system packet
u32 totalSlotNum;//total slot number that already tranfferred
u32 mediaAlignSz;//nand write align size, 16K/32k
u32 nextWriteBackSlot;//when reach n* (writeBackUnitSz/transferUnitSz), then write back the recevied data to media
u32 leftDataSz;//left data size, Assert that 'leftDataInBackBuf + leftDataSz == transferBuf'
s16 isUpload;
s16 pktTransferSta;
u32 destMediaType;
u32 partBaseOffset;//TODO: change it to memory address when dest media type is memory
u32 itemOffsetNotAlignClusterSz_f;//For sdcard burning, item offset of aml_upgrade_package.img is not aligned to bytespercluster of FAT fs(_f means not changed inited)
}BufManager;
//TODO: if want to speed-up such as soft PING-PONG buffer, use multiple BufManager
static BufManager _bufManager =
{
//constant members
.transferBuf = (const u8*)OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR,
.transferBufSz = OPTIMUS_DOWNLOAD_TRANSFER_BUF_TOTALSZ,
.transferUnitSz = OPTIMUS_DOWNLOAD_SLOT_SZ,
//different for each command, note a command corresponding to a download file
//must create/destroy for a command
.writeBackUnitSz = OPTIMUS_DOWNLOAD_SLOT_SZ,
.totalSlotNum = 0,//not slot data recevied yet!
.leftDataSz = 0,
.tplcmdTotalSz = 0,
.nextWriteBackSlot = 0,//always 0 when upload??
.isUpload = 0,
.pktTransferSta = PKT_TRANSFER_STA_EMPTY,
.itemOffsetNotAlignClusterSz_f = 0,
};
int optimus_buf_manager_init(const unsigned mediaAlignSz)
{
if (OPTIMUS_DOWNLOAD_TRANSFER_BUF_ADDR != (uint64_t)_bufManager.transferBuf) {
DWN_ERR("Fatal fail in init-express, init here instead!\n");
return OPT_DOWN_FAIL;
}
_bufManager.mediaAlignSz = mediaAlignSz;
DWN_DBG("transfer=0x%p, transferBufSz=0x%x, transferUnitSz=0x%x, writeBackUnitSz=0x%x, totalSlotNum=%d\n", _bufManager.transferBuf,
_bufManager.transferBufSz, _bufManager.transferUnitSz, _bufManager.writeBackUnitSz, _bufManager.totalSlotNum);
return OPT_DOWN_OK;
}
int optimus_buf_manager_exit(void)
{
return 0;
}
int optimus_buf_manager_tplcmd_init(const char* mediaType, const char* partName, const u64 partBaseOffset,
const char* imgType, const u64 pktTotalSz, const int isUpload,
const unsigned itemSizeNotAligned /* if item offset 3 and bytepercluste 4k, then it's 4k -3 */)
{
u32 writeBackUnitSz = OPTIMUS_VFAT_IMG_WRITE_BACK_SZ;
const u64 pktSz4BufManager = pktTotalSz - itemSizeNotAligned;
int cacheAll2Mem = 0;
#if OPTIMUS_BURN_TARGET_SUPPORT_UBIFS
if ( !strcmp(imgType, "ubifs") ) cacheAll2Mem = 1;
#endif // #if OPTIMUS_BURN_TARGET_SUPPORT_UBIFS
if (!strcmp("sparse", imgType)
|| itemSizeNotAligned/* use max memory if item 'itemOffset % bytespercluster != 0'*/)
{
writeBackUnitSz = OPTIMUS_SIMG_WRITE_BACK_SZ;
}
if (!strcmp("bootloader", partName) || !strcmp("_aml_dtb", partName)
#if defined(CONFIG_AML_MTD) && defined(CONFIG_TPL_PART_NAME)
|| ( !strcmp(CONFIG_TPL_PART_NAME, partName) )
#endif//#if defined(CONFIG_AML_MTD)
)
{
if (pktSz4BufManager > _bufManager.transferBufSz) {
DWN_ERR("packet size 0x%x too large, max is 0x%x\n", (u32)pktSz4BufManager, _bufManager.transferBufSz);
return OPT_DOWN_FAIL;
}
/*writeBackUnitSz = OPTIMUS_BOOTLOADER_MAX_SZ;*/
writeBackUnitSz = pktSz4BufManager + _bufManager.transferUnitSz - 1;
writeBackUnitSz >>= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS;
writeBackUnitSz <<= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS;
}
_bufManager.destMediaType = !strcmp("mem", mediaType) ? OPTIMUS_MEDIA_TYPE_MEM : OPTIMUS_MEDIA_TYPE_STORE ;
if ( !cacheAll2Mem ) cacheAll2Mem = !strcmp("mem", mediaType) ;
if (cacheAll2Mem)
{
writeBackUnitSz = pktSz4BufManager + _bufManager.transferUnitSz - 1;
writeBackUnitSz >>= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS;
writeBackUnitSz <<= OPTIMUS_DOWNLOAD_SLOT_SZ_SHIFT_BITS;
if (partBaseOffset>>32) {
DWN_ERR("partBaseOffset 0x%llx more than 4G!!\n", partBaseOffset);
return OPT_DOWN_FAIL;
}
_bufManager.partBaseOffset = (u32)partBaseOffset;
}
if (_bufManager.transferBufSz < writeBackUnitSz && !cacheAll2Mem) {
DWN_ERR("write back size 0x%x > max size 0x%x\n", writeBackUnitSz, _bufManager.transferBufSz);
return OPT_DOWN_FAIL;
}
if (_bufManager.transferUnitSz > writeBackUnitSz) {
DWN_ERR("write back size %d < align size %d\n", writeBackUnitSz, _bufManager.mediaAlignSz);
return OPT_DOWN_FAIL;
}
DWN_DBG("writeBackUnitSz = 0x%x, pktSz4BufManager = %lld\n", writeBackUnitSz, pktSz4BufManager);
_bufManager.writeBackUnitSz = writeBackUnitSz;
_bufManager.totalSlotNum = 0;
_bufManager.isUpload = isUpload;
_bufManager.pktTransferSta = PKT_TRANSFER_STA_EMPTY;
if (_bufManager.isUpload)
{
_bufManager.nextWriteBackSlot = 0;//always 0 if upload
}
else//has write back if download
{
if (pktSz4BufManager < writeBackUnitSz)
{
_bufManager.nextWriteBackSlot = ((u32)pktSz4BufManager + _bufManager.transferUnitSz - 1)/_bufManager.transferUnitSz;//first slot index to write back to media
}
else
{
_bufManager.nextWriteBackSlot = writeBackUnitSz/_bufManager.transferUnitSz;//first slot index to write back to media
}
}
_bufManager.itemOffsetNotAlignClusterSz_f = itemSizeNotAligned;
_bufManager.leftDataSz = itemSizeNotAligned;//data size in the buffer that not write back to media yet in previous transfer
_bufManager.tplcmdTotalSz = pktSz4BufManager;
optimus_progress_init((u32)(_bufManager.tplcmdTotalSz>>32), (u32)_bufManager.tplcmdTotalSz, 0, 100);
DWN_MSG("totalSlotNum = %d, nextWriteBackSlot %d\n", _bufManager.totalSlotNum, _bufManager.nextWriteBackSlot);
return OPT_DOWN_OK;
}
int optimus_buf_manager_get_buf_for_bulk_transfer(char** pBuf, const unsigned wantSz, const unsigned sequenceNo, char* errInfo)
{
const unsigned totalSlotNum = _bufManager.totalSlotNum;
const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz;//data size already transferred
const u64 leftPktSz = (totalTransferSz > _bufManager.tplcmdTotalSz) ? 0 :(_bufManager.tplcmdTotalSz - totalTransferSz);
const int isLastTransfer = (leftPktSz == wantSz);//totalTransferSz + wantSz >= _bufManager.tplcmdTotalSz;
const u32 bufSzNotDisposed = ((u32)totalTransferSz)% _bufManager.writeBackUnitSz;//buffer data not disposed, bufSz is always writeBackUnitSz
const u8* BufBase = (OPTIMUS_MEDIA_TYPE_MEM != _bufManager.destMediaType) ? _bufManager.transferBuf :
(u8*)(u64)_bufManager.partBaseOffset ;
if (wantSz < _bufManager.transferUnitSz && !isLastTransfer) {
DWN_ERR("only last transfer can less 64K, this index %d at size 0x%u illegle\n", totalSlotNum + 1, wantSz);
return OPT_DOWN_FAIL;
}
//TODO: totalSlotNum + 1 == sequenceNo
if (totalSlotNum + 1 != sequenceNo) {//ASSERT it ??
}
*pBuf = (char*)(bufSzNotDisposed + BufBase);
DWN_DBG("bufSzNotDisposed 0x%x, _bufManager.transferBuf 0x%p, _bufManager.partBaseOffset 0x%x, *pBuf 0x%p\n",
bufSzNotDisposed, _bufManager.transferBuf, _bufManager.partBaseOffset, *pBuf);
_bufManager.pktTransferSta = PKT_TRANSFER_STA_WORKING;
//prepare data for upload
if (!bufSzNotDisposed && _bufManager.isUpload)
{
u32 wantSz = (leftPktSz > _bufManager.writeBackUnitSz) ? _bufManager.writeBackUnitSz : ((u32)leftPktSz);
DWN_DBG("want size 0x%x\n", wantSz);
u32 readSz = optimus_dump_storage_data((u8*)BufBase, wantSz, errInfo);
if (readSz != wantSz) {
DWN_ERR("Want read %u, but %u\n", wantSz, readSz);
return OPT_DOWN_FAIL;
}
}
return OPT_DOWN_OK;
}
int optimus_buf_manager_report_transfer_complete(const u32 transferSz, char* errInfo)
{
const unsigned totalSlotNum = _bufManager.totalSlotNum;
const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz + transferSz;
const u64 leftPktSz = (totalTransferSz > _bufManager.tplcmdTotalSz) ? 0 :(_bufManager.tplcmdTotalSz - totalTransferSz);
const u32 thisWriteBackSz = (_bufManager.transferUnitSz == transferSz) ? _bufManager.writeBackUnitSz : ((u32)totalTransferSz % _bufManager.writeBackUnitSz);
const u8* BufBase = (OPTIMUS_MEDIA_TYPE_MEM != _bufManager.destMediaType) ? _bufManager.transferBuf :
(u8*)(u64)_bufManager.partBaseOffset ;
DWN_DBG("transferSz=0x%x\n", transferSz);
//state fileds to update
_bufManager.totalSlotNum += 1;
if (_bufManager.totalSlotNum == _bufManager.nextWriteBackSlot)
{
u32 burnSz = 0;
u32 leftSz = _bufManager.leftDataSz;//data size not write to media in previous write back, > 0 only when not normal packet
const u32 size = leftSz + thisWriteBackSz;
const u8* data = (u8*)BufBase -leftSz;
const unsigned reserveNotAlignSz = leftPktSz ? _bufManager.itemOffsetNotAlignClusterSz_f : 0;//reserve
//call cb function to write to media
DWN_DBG("size 0x%x, reserveNotAlignSz 0x%x\n", size, reserveNotAlignSz);
burnSz = optimus_download_img_data(data, size - reserveNotAlignSz, errInfo);
if (burnSz <= leftSz || !burnSz) {
DWN_ERR("this burn size %d <= last left size %d, data 0x%p\n", burnSz, leftSz, data);
return OPT_DOWN_FAIL;
}
if (size - reserveNotAlignSz < burnSz) {
DWN_ERR("Exception:siz 0x%x < burnSz 0x%x\n", size - reserveNotAlignSz, burnSz);
return OPT_DOWN_FAIL;
}
leftSz = size - burnSz;
if (leftSz)
{
const u8* src = data + burnSz;
u8* dest = (u8*)BufBase - leftSz;
if (totalTransferSz >= _bufManager.tplcmdTotalSz) {
DWN_ERR("Exception:packet end but data left 0x%x, totalTransferSz 0x%llx, cmd sz 0x%llx!\n",
leftSz, totalTransferSz, _bufManager.tplcmdTotalSz);
return OPT_DOWN_FAIL;
}
if (leftSz > OPTIMUS_SPARSE_IMG_LEFT_DATA_MAX_SZ) {
DWN_ERR("Exception, left data sz 0x%x > back buf sz 0x%x!\n", leftSz, OPTIMUS_SPARSE_IMG_LEFT_DATA_MAX_SZ);
return OPT_DOWN_FAIL;
}
if (leftSz & 0x03) {
DWN_ERR("Exception, copy size not align to 4! May will copy fail!\n");
return OPT_DOWN_FAIL;
}
DWN_DBG("MV:left size 0x%08x, src %p, dest %p\n", leftSz, src, dest);
memcpy(dest, src, leftSz);
}
//update _bufManager.leftDataSz and _bufManager.nextWriteBackSlot
_bufManager.leftDataSz = leftSz;
if (leftPktSz >= _bufManager.writeBackUnitSz)
{
_bufManager.nextWriteBackSlot += _bufManager.writeBackUnitSz/_bufManager.transferUnitSz;
}
else
{
_bufManager.nextWriteBackSlot += ((u32)leftPktSz + _bufManager.transferUnitSz - 1)/_bufManager.transferUnitSz;
}
}
optimus_update_progress(transferSz);//report burning steps
return OPT_DOWN_OK;
}
int is_largest_data_transferring(void)
{
const unsigned totalSlotNum = _bufManager.totalSlotNum;
const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz;//data size already transferred
return (PKT_TRANSFER_STA_WORKING == _bufManager.pktTransferSta)
&& (_bufManager.tplcmdTotalSz > totalTransferSz);//as last packet may less than 64k, var totalSlotNum may > _bufManager.tplcmdTotalSz
}
int set_largest_data_transfer_sta_end(void)
{
_bufManager.pktTransferSta = PKT_TRANSFER_STA_END;
return 0;
}
//command data format: [0-3]reserver, [4-7]dataLen, [8-11]sequence number, [12-15]check sum
int optimus_buf_manager_get_command_data_for_upload_transfer(u8* cmdDataBuf, const unsigned bufLen)
{
const unsigned totalSlotNum = _bufManager.totalSlotNum;
const u64 totalTransferSz = ((u64)totalSlotNum) * _bufManager.transferUnitSz;
const u64 leftPktSz = (totalTransferSz > _bufManager.tplcmdTotalSz) ? 0 :(_bufManager.tplcmdTotalSz - totalTransferSz);
const unsigned thisTransDataLen = (leftPktSz > _bufManager.transferUnitSz) ? _bufManager.transferUnitSz : ((u32)leftPktSz);
DWN_DBG("thisTransDataLen 0x%x, left 0x%x, total 0x%x\n", thisTransDataLen, (u32)leftPktSz, (u32)totalTransferSz);
DWN_DBG("totalSlotNum %d, totalTransferSz 0x%x\n", totalSlotNum, (u32)totalTransferSz);
memset(cmdDataBuf, bufLen, 0);
*(unsigned*)(cmdDataBuf + 0) = 0xefe8;
*(unsigned*)(cmdDataBuf + 4) = thisTransDataLen;//Fill transfer data length of this bulk transfer
_bufManager.pktTransferSta = PKT_TRANSFER_STA_WORKING;
return 0;
}