first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

@@ -0,0 +1,433 @@
// Copyright (C) 2010 Apple Inc. All rights reserved.
//
// This document is the property of Apple Inc.
// It is considered confidential and proprietary.
//
// This document may not be reproduced or transmitted in any form,
// in whole or in part, without the express written permission of
// Apple Inc.
//
//
//
//
#include "WMROAM.h"
#include "WMRBuf.h"
#include "ANDTypes.h"
#include "WMRTest.h"
#include "FTL.h"
#include "PPN_FIL.h"
#include "PPNMiscTypes.h"
#include "WMRConfig.h"
////////////////////////////////////////////////////////////////////////////////
// Local types
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////////////////
#define AND_MAX_BANKS (AND_MAX_BANKS_PER_CS * 4)
#define AND_MAX_CHANNELS (2)
#define TEST_DATA_WATERMARK (0xB6)
#define TEST_META_WATERMARK (0xC7)
#define TEST_STATS_WATERMARK (0xD8)
#define TEST_MAX_PAGES_PER_OP (2)
#define TEST_DUMP_ON_MISCOMPARE (0)
#define PPN_COMMAND_PROGRAM (2UL)
#define PPN_COMMAND_ERASE (3UL)
////////////////////////////////////////////////////////////////////////////////
// Static function declarations
////////////////////////////////////////////////////////////////////////////////
static BOOL32 FILInterfaceTest(UInt16 *blockList);
static BOOL32 InitTestInfo(void);
static void FillBufferWithCountingPattern(UInt8 *buffer, UInt32 startValue, UInt32 bytes);
#if TEST_DUMP_ON_MISCOMPARE
static void FILTestHexdump(void *data, UInt32 length);
#endif // TEST_DUMP_ON_MISCOMPARE
////////////////////////////////////////////////////////////////////////////////
// Static variables
typedef struct
{
UInt32 pagesPerBlock;
UInt32 numCE;
UInt32 bootPageBytes;
UInt32 correctableSectorsPerPage;
} FILTestInfo;
static FILTestInfo testInfo;
static PPN_DeviceInfo devInfo;
static LowFuncTbl *pFIL = NULL;
static WMR_BufZone_t bufZone;
////////////////////////////////////////////////////////////////////////////////
// Public functions
////////////////////////////////////////////////////////////////////////////////
// Entry point
BOOL32
WMR_FIL_Test
(LowFuncTbl *fil)
{
pFIL = fil;
//return TRUE32;
return FIL_Test();
}
BOOL32 FIL_Test()
{
UInt16 blockList[AND_MAX_BANKS];
WMR_MEMSET(blockList, 0, sizeof(UInt16) * AND_MAX_BANKS);
WMR_BufZone_Init(&bufZone);
InitTestInfo();
ppnMiscFillDevStruct(&devInfo, pFIL);
return FILInterfaceTest(blockList);
}
// Local functions
BOOL32 InitTestInfo(void)
{
testInfo.pagesPerBlock = pFIL->GetDeviceInfo(AND_DEVINFO_PAGES_PER_BLOCK);
WMR_ASSERT(testInfo.pagesPerBlock > 0);
testInfo.numCE = pFIL->GetDeviceInfo(AND_DEVINFO_NUM_OF_CES_PER_CHANNEL) * pFIL->GetDeviceInfo(AND_DEVINFO_NUM_OF_CHANNELS);
WMR_ASSERT(testInfo.numCE > 0);
testInfo.bootPageBytes = pFIL->GetDeviceInfo(AND_DEVINFO_BYTES_PER_BL_PAGE);
WMR_ASSERT(testInfo.bootPageBytes > 0);
return TRUE32;
}
// Block list is assumed to be numBanks long and non-overlapping banks
BOOL32 isClean(UInt8 *buf, UInt32 size)
{
UInt32 i;
for (i=0; i<size; i++)
{
if (buf[i] != 0xFF)
{
return FALSE32;
}
}
return TRUE32;
}
BOOL32 FILInterfaceTest(UInt16 *blockList)
{
BOOL32 ret = FALSE32;
UInt8 *writeDataBuffer = NULL;
UInt8 *writeMetaBuffer = NULL;
UInt8 *verifyDataBuffer = NULL;
UInt8 *verifyMetaBuffer = NULL;
UInt32 testSeed = 1234567890;
const UInt32 dataPerPage = devInfo.main_bytes_per_lba * devInfo.lbas_per_page;
const UInt32 metaPerPage = devInfo.lba_meta_bytes_buffer * devInfo.lbas_per_page;
const UInt32 dataBufferSize = devInfo.num_of_banks * dataPerPage * TEST_MAX_PAGES_PER_OP;
const UInt32 metaBufferSize = devInfo.num_of_banks * metaPerPage * TEST_MAX_PAGES_PER_OP;
PPNCommandStruct *ppnCmd[AND_MAX_CHANNELS];
PPNReorderStruct *ppnReorder;
UInt32 bank = 0;
UInt32 page = 0;
UInt32 channel, lba;
WMR_PRINT(ALWAYS, "Starting FIL Interface Test\n");
writeMetaBuffer = WMR_Buf_Alloc_ForDMA(&bufZone, metaBufferSize);
verifyMetaBuffer = WMR_Buf_Alloc_ForDMA(&bufZone, metaBufferSize);
writeDataBuffer = WMR_Buf_Alloc_ForDMA(&bufZone, dataBufferSize);
verifyDataBuffer = WMR_Buf_Alloc_ForDMA(&bufZone, dataBufferSize);
for (channel = 0 ; channel < devInfo.num_channels ; channel++)
{
ppnCmd[channel] = WMR_Buf_Alloc_ForDMA(&bufZone, sizeof(PPNCommandStruct));
}
WMR_BufZone_FinishedAllocs(&bufZone);
WMR_BufZone_Rebase(&bufZone, (void **)&writeMetaBuffer);
WMR_BufZone_Rebase(&bufZone, (void **)&verifyMetaBuffer);
WMR_BufZone_Rebase(&bufZone, (void **)&writeDataBuffer);
WMR_BufZone_Rebase(&bufZone, (void **)&verifyDataBuffer);
for (channel = 0 ; channel < devInfo.num_channels ; channel++)
{
WMR_BufZone_Rebase(&bufZone, (void **)&ppnCmd[channel]);
}
if (!writeDataBuffer || !writeMetaBuffer || !verifyDataBuffer || !verifyMetaBuffer)
{
WMR_PANIC("Buffer allocations failed");
goto exit;
}
WMR_BufZone_FinishedRebases(&bufZone);
ppnReorder = WMR_MALLOC(sizeof(PPNReorderStruct));
ppnMiscInitCommandStructure(&devInfo, ppnCmd, devInfo.num_channels, PPN_COMMAND_ERASE, PPN_NO_OPTIONS);
// Erase Block
WMR_PRINT(ALWAYS, "Erasing CAU %d Block %d\n", bank, (UInt32) blockList[0]);
ppnMiscSingleOperation(&devInfo, ppnCmd[0], PPN_COMMAND_ERASE, PPN_NO_OPTIONS, bank, blockList[0], page, FALSE32, NULL, NULL);
if (ppnCmd[0]->page_status_summary != 0x40)
{
WMR_PRINT(ALWAYS, "Erase failed with summary status = 0x%x\n", ppnCmd[0]->page_status_summary);
goto exit;
}
// Clean check single page
WMR_PRINT(ALWAYS, "Clean checking CAU %d Block %d Page %d\n", bank, blockList[0], page);
WMR_MEMSET(verifyDataBuffer, TEST_DATA_WATERMARK, dataPerPage);
WMR_MEMSET(verifyMetaBuffer, TEST_META_WATERMARK, metaPerPage);
ppnMiscInitCommandStructure(&devInfo, ppnCmd, devInfo.num_channels, PPN_COMMAND_READ, PPN_NO_OPTIONS);
for (lba = 0 ; lba < devInfo.lbas_per_page ; lba++)
{
ppnMiscAddPhysicalAddressToCommandStructure(&devInfo, ppnCmd,
ppnMiscGetChannelFromBank(&devInfo, bank),
ppnMiscGetCEIdxFromBank(&devInfo, bank),
ppnMiscGetCAUFromBank(&devInfo, bank),
blockList[0], 0, FALSE32, devInfo.lbas_per_page - 1 - lba, 1, lba, 0);
ppnMiscAddMemoryToCommandStructure(&devInfo, ppnCmd, devInfo.num_channels,
&verifyDataBuffer[lba * devInfo.main_bytes_per_lba],
&verifyMetaBuffer[lba * devInfo.lba_meta_bytes_buffer],
1);
}
WMR_MEMSET(verifyDataBuffer, TEST_DATA_WATERMARK, dataBufferSize);
WMR_MEMSET(verifyMetaBuffer, TEST_META_WATERMARK, metaBufferSize);
ppnMiscReorderCommandStruct(&devInfo, ppnCmd, devInfo.num_channels, ppnReorder);
pFIL->PerformCommandList(ppnCmd, 1);
for (lba = 0 ; lba < devInfo.lbas_per_page ; lba++)
{
WMR_PRINT(ALWAYS, "ppnCmd[0]->entry[%d].status = 0x%08x\n", lba, ppnCmd[0]->entry[lba].status);
}
if (ppnCmd[0]->page_status_summary != 0x49)
{
WMR_PRINT(ALWAYS, "Clean check single page failed with summary status = 0x%x\n", ppnCmd[0]->page_status_summary);
goto exit;
}
if (isClean(verifyDataBuffer, dataPerPage) == FALSE32)
{
WMR_PRINT(ALWAYS, "Clean Detect failed: Main!\n");
//goto exit;
}
if (isClean(verifyMetaBuffer, metaPerPage) == FALSE32)
{
WMR_PRINT(ALWAYS, "Clean Detect failed: Meta!\n");
//goto exit;
}
// Program single page
WMR_PRINT(ALWAYS, "Writing single page CAU %d Block %d Page %d\n", bank, blockList[0], page);
FillBufferWithCountingPattern(writeDataBuffer, testSeed++, dataPerPage);
FillBufferWithCountingPattern(writeMetaBuffer, testSeed++, metaPerPage);
ppnMiscSingleOperation(&devInfo, ppnCmd[0], PPN_COMMAND_PROGRAM, PPN_NO_OPTIONS, bank, blockList[0], page, FALSE32, writeDataBuffer, writeMetaBuffer);
if (ppnCmd[0]->page_status_summary != 0x62)
{
WMR_PRINT(ALWAYS, "Program single page failed with summary status = 0x%x\n", ppnCmd[0]->page_status_summary);
goto exit;
}
// Read back and verify
WMR_PRINT(ALWAYS, "Reading back single page CAU %d Block %d Page %d\n", bank, blockList[0], page);
WMR_MEMSET(verifyDataBuffer, TEST_DATA_WATERMARK, dataPerPage);
WMR_MEMSET(verifyMetaBuffer, TEST_META_WATERMARK, metaPerPage);
ppnMiscSingleOperation(&devInfo, ppnCmd[0], PPN_COMMAND_READ, PPN_NO_OPTIONS, bank, blockList[0], page, FALSE32, verifyDataBuffer, verifyMetaBuffer);
if (ppnCmd[0]->page_status_summary != 0x40)
{
WMR_PRINT(ALWAYS, "Read back single page failed with summary status = 0x%x\n", ppnCmd[0]->page_status_summary);
goto exit;
}
if (WMR_MEMCMP(writeMetaBuffer, verifyMetaBuffer, metaPerPage))
{
WMR_PRINT(ALWAYS, "Read back contents failed comparison in meta section\n");
#if TEST_DUMP_ON_MISCOMPARE
WMR_PRINT(ALWAYS, "Expected:\n");
FILTestHexdump(writeMetaBuffer, metaPerPage);
WMR_PRINT(ALWAYS, "Actual:\n");
FILTestHexdump(verifyMetaBuffer, metaPerPage);
#endif // TEST_DUMP_ON_MISCOMPARE
goto exit;
}
if (WMR_MEMCMP(writeDataBuffer, verifyDataBuffer, dataPerPage))
{
WMR_PRINT(ALWAYS, "Read back contents failed comparison in data section\n");
#if TEST_DUMP_ON_MISCOMPARE
WMR_PRINT(ALWAYS, "Expected:\n");
FILTestHexdump(writeDataBuffer, dataPerPage);
WMR_PRINT(ALWAYS, "Actual:\n");
FILTestHexdump(verifyDataBuffer, dataPerPage);
#endif // TEST_DUMP_ON_MISCOMPARE
goto exit;
}
// MultiBlockErase (Block from all bank)
WMR_PRINT(ALWAYS, "Erasing Block %d from all banks\n", blockList[0]);
ppnMiscInitCommandStructure(&devInfo, ppnCmd, devInfo.num_channels, PPN_COMMAND_ERASE, PPN_NO_OPTIONS);
for (bank=0; bank<devInfo.num_of_banks; bank++)
{
ppnMiscAddPhysicalAddressToCommandStructure(&devInfo, ppnCmd,
ppnMiscGetChannelFromBank(&devInfo, bank),
ppnMiscGetCEIdxFromBank(&devInfo, bank),
ppnMiscGetCAUFromBank(&devInfo, bank),
blockList[0], 0, FALSE32, 0, 0, bank, 0);
ppnMiscAddMemoryToCommandStructure(&devInfo, ppnCmd, devInfo.num_channels,
NULL,
NULL,
devInfo.lbas_per_page);
}
ppnMiscReorderCommandStruct(&devInfo, ppnCmd, devInfo.num_channels, ppnReorder);
pFIL->PerformCommandList(ppnCmd, devInfo.num_channels);
for (channel = 0 ; channel < devInfo.num_channels ; channel++)
{
if (ppnCmd[channel]->page_status_summary != 0x40)
{
WMR_PRINT(ALWAYS, "MultiBlockErase failed with summary status = 0x%x\n", ppnCmd[channel]->page_status_summary);
goto exit;
}
}
// MultiPageProgram (Program 2 pages on each bank)
WMR_PRINT(ALWAYS, "Multipage Programming %d pages of Block %d of each bank\n", TEST_MAX_PAGES_PER_OP, blockList[0]);
ppnMiscInitCommandStructure(&devInfo, ppnCmd, devInfo.num_channels, PPN_COMMAND_PROGRAM, PPN_NO_OPTIONS);
for (bank=0; bank<devInfo.num_of_banks; bank++)
{
for (page = 0 ; TEST_MAX_PAGES_PER_OP > page ; page++)
{
ppnMiscAddPhysicalAddressToCommandStructure(&devInfo, ppnCmd,
ppnMiscGetChannelFromBank(&devInfo, bank),
ppnMiscGetCEIdxFromBank(&devInfo, bank),
ppnMiscGetCAUFromBank(&devInfo, bank),
blockList[0], page, FALSE32, 0, devInfo.lbas_per_page, bank*2+page, 0);
ppnMiscAddMemoryToCommandStructure(&devInfo, ppnCmd, devInfo.num_channels,
&writeDataBuffer[(bank*2+page) * dataPerPage],
&writeMetaBuffer[(bank*2+page) * metaPerPage],
devInfo.lbas_per_page);
}
}
FillBufferWithCountingPattern(writeDataBuffer, testSeed++, dataBufferSize);
FillBufferWithCountingPattern(writeMetaBuffer, testSeed++, metaBufferSize);
ppnMiscReorderCommandStruct(&devInfo, ppnCmd, devInfo.num_channels, ppnReorder);
pFIL->PerformCommandList(ppnCmd, devInfo.num_channels);
for (channel = 0 ; channel < devInfo.num_channels ; channel++)
{
if (ppnCmd[channel]->page_status_summary != 0x62)
{
WMR_PRINT(ALWAYS, "Multipage Program failed with summary status = 0x%x\n", ppnCmd[channel]->page_status_summary);
goto exit;
}
}
// MultiPageRead (Read 2 pages on each bank)
WMR_PRINT(ALWAYS, "Multipage Read of %d pages of Block %d of each bank\n", TEST_MAX_PAGES_PER_OP, blockList[0]);
ppnMiscInitCommandStructure(&devInfo, ppnCmd, devInfo.num_channels, PPN_COMMAND_READ, PPN_NO_OPTIONS);
for (bank=0; bank<devInfo.num_of_banks; bank++)
{
for (page = 0 ; TEST_MAX_PAGES_PER_OP > page ; page++)
{
ppnMiscAddPhysicalAddressToCommandStructure(&devInfo, ppnCmd,
ppnMiscGetChannelFromBank(&devInfo, bank),
ppnMiscGetCEIdxFromBank(&devInfo, bank),
ppnMiscGetCAUFromBank(&devInfo, bank),
blockList[0], page, FALSE32, 0, devInfo.lbas_per_page, bank*2+page, 0);
ppnMiscAddMemoryToCommandStructure(&devInfo, ppnCmd, devInfo.num_channels,
&verifyDataBuffer[(bank*2+page) * dataPerPage],
&verifyMetaBuffer[(bank*2+page) * metaPerPage],
devInfo.lbas_per_page);
}
}
WMR_MEMSET(verifyDataBuffer, TEST_DATA_WATERMARK, dataBufferSize);
WMR_MEMSET(verifyMetaBuffer, TEST_META_WATERMARK, metaBufferSize);
ppnMiscReorderCommandStruct(&devInfo, ppnCmd, devInfo.num_channels, ppnReorder);
pFIL->PerformCommandList(ppnCmd, devInfo.num_channels);
for (channel = 0 ; channel < devInfo.num_channels ; channel++)
{
if (ppnCmd[channel]->page_status_summary != 0x40)
{
WMR_PRINT(ALWAYS, "Multipage Read failed with summary status = 0x%x\n", ppnCmd[channel]->page_status_summary);
goto exit;
}
}
if (WMR_MEMCMP(writeMetaBuffer, verifyMetaBuffer, metaBufferSize))
{
WMR_PRINT(ALWAYS, "Read back contents failed comparison in meta section\n");
#if TEST_DUMP_ON_MISCOMPARE
WMR_PRINT(ALWAYS, "Expected:\n");
FILTestHexdump(writeMetaBuffer, metaBufferSize);
WMR_PRINT(ALWAYS, "Actual:\n");
FILTestHexdump(verifyMetaBuffer, metaBufferSize);
#endif // TEST_DUMP_ON_MISCOMPARE
goto exit;
}
if (WMR_MEMCMP(writeDataBuffer, verifyDataBuffer, dataBufferSize))
{
WMR_PRINT(ALWAYS, "Read back contents failed comparison in data section\n");
#if TEST_DUMP_ON_MISCOMPARE
WMR_PRINT(ALWAYS, "Expected:\n");
FILTestHexdump(writeDataBuffer, dataBufferSize);
WMR_PRINT(ALWAYS, "Actual:\n");
FILTestHexdump(verifyDataBuffer, dataBufferSize);
#endif // TEST_DUMP_ON_MISCOMPARE
goto exit;
}
ret = TRUE32;
exit:
WMR_PRINT(ALWAYS, "Interface Test %s\n", ret ? "Passed" : "Failed");
if (ppnReorder)
{
WMR_FREE(ppnReorder, sizeof(PPNReorderStruct));
}
WMR_BufZone_Free(&bufZone);
return ret;
}
static void FillBufferWithCountingPattern(UInt8 *buffer, UInt32 value, UInt32 bytes)
{
UInt32 *word;
if (0 != bytes % sizeof(*word))
{
const UInt32 extra = bytes % sizeof(*word);
bytes -= extra;
WMR_MEMCPY(&buffer[bytes], &value, extra);
value++;
}
while (0 < bytes)
{
bytes -= sizeof(*word);
word = (UInt32 *)&buffer[bytes];
*word = value++;
}
}
#if TEST_DUMP_ON_MISCOMPARE
#define HEXDUMP_WIDTH (16)
static void FILTestHexdump(void *data, UInt32 length)
{
UInt32 i, j;
UInt8 *bytes = (UInt8*) data;
for (i = 0; i < length; i += HEXDUMP_WIDTH)
{
for (j = 0; (j < HEXDUMP_WIDTH) && ((i + j) < length); j++)
{
_WMR_PRINT(" %02x", (UInt32) *bytes++);
}
_WMR_PRINT("\n");
}
}
#endif // TEST_DUMP_ON_MISCOMPARE
@@ -0,0 +1,45 @@
// Copyright (C) 2010 Apple Inc. All rights reserved.
//
// This document is the property of Apple Inc.
// It is considered confidential and proprietary.
//
// This document may not be reproduced or transmitted in any form,
// in whole or in part, without the express written permission of
// Apple Inc.
//
//
//
// Just call WMR_FPart_Test() with an init'ed FPart
//
#include "WMROAM.h"
#include "WMRBuf.h"
#include "ANDTypes.h"
#include "WMRTest.h"
#include "FPart.h"
////////////////////////////////////////////////////////////////////////////////
// Local types
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Static variables
////////////////////////////////////////////////////////////////////////////////
// Static function declarations
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Public functions
////////////////////////////////////////////////////////////////////////////////
// Entry point
BOOL32
WMR_FPart_Test
(FPartFunctions *fpart)
{
return TRUE32;
}
@@ -0,0 +1,45 @@
// Copyright (C) 2010 Apple Inc. All rights reserved.
//
// This document is the property of Apple Inc.
// It is considered confidential and proprietary.
//
// This document may not be reproduced or transmitted in any form,
// in whole or in part, without the express written permission of
// Apple Inc.
//
//
//
// Just call WMR_FTL_Test() with an opened FTL
//
#include "WMROAM.h"
#include "WMRBuf.h"
#include "ANDTypes.h"
#include "WMRTest.h"
#include "FTL.h"
////////////////////////////////////////////////////////////////////////////////
// Local types
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Static variables
////////////////////////////////////////////////////////////////////////////////
// Static function declarations
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Public functions
////////////////////////////////////////////////////////////////////////////////
// Entry point
BOOL32
WMR_FTL_Test
(FTLFunctions *ftl)
{
return TRUE32;
}
@@ -0,0 +1,426 @@
// Copyright (C) 2010 Apple Inc. All rights reserved.
//
// This document is the property of Apple Inc.
// It is considered confidential and proprietary.
//
// This document may not be reproduced or transmitted in any form,
// in whole or in part, without the express written permission of
// Apple Inc.
//
//
//
// Just call WMR_VFL_Test() with an opened VFL. Test will run on burnin
// area, leaving FTL untouched
//
#include "WMROAM.h"
#include "WMRBuf.h"
#include "ANDTypes.h"
#include "VFL.h"
#define SVFL 0
////////////////////////////////////////////////////////////////////////////////
// Local types
////////////////////////////////////////////////////////////////////////////////
typedef struct
{
UInt16 num_ftl_vb;
UInt16 num_total_vb;
UInt16 pages_per_vb;
UInt16 bytes_per_page;
UInt32 lba_per_page;
UInt32 bytes_per_meta;
}VFLTestInfo;
typedef struct
{
void * write_main;
void * write_meta;
void * verify_main;
void * verify_meta;
UInt32 * virtual_page_list;
}VFLTestBuffers;
////////////////////////////////////////////////////////////////////////////////
// Static variables
////////////////////////////////////////////////////////////////////////////////
static VFLFunctions *_vfl = NULL;
static VFLTestInfo _test_info;
static VFLTestBuffers _buf;
VFLTestBuffers *my_vfl_test_buffers = &_buf; // convenience pointer
#if(SVFL)
static VFL_ReadSpans_t s;
#endif
////////////////////////////////////////////////////////////////////////////////
// Static function declarations
////////////////////////////////////////////////////////////////////////////////
static BOOL32
_GetVFLUInt16
(UInt32 struct_name,
UInt16 *value);
static BOOL32
_GetVFLUInt32
(UInt32 struct_name,
UInt32 *value);
static BOOL32
_GetTestInfo
(void);
static void
_FillBuffer
(UInt8 *buffer,
UInt32 size,
UInt8 seed);
static void
_FillSwissMetaBuffer
(UInt8 *buffer,
UInt32 size,
UInt8 seed);
static BOOL32
_RunSequentialTest
(void);
////////////////////////////////////////////////////////////////////////////////
// Public functions
////////////////////////////////////////////////////////////////////////////////
// Entry point
BOOL32
WMR_VFL_Test
(VFLFunctions *vfl)
{
WMR_BufZone_t zone;
BOOL32 result = TRUE32;
WMR_MEMSET(&_test_info, 0, sizeof(_test_info));
WMR_MEMSET(&_buf, 0, sizeof(_buf));
_vfl = vfl;
if (!_GetTestInfo())
{
return FALSE32;
}
WMR_BufZone_Init(&zone);
_buf.write_main = WMR_Buf_Alloc_ForDMA(&zone,
_test_info.pages_per_vb * _test_info.bytes_per_page);
_buf.write_meta = WMR_Buf_Alloc_ForDMA(&zone,
_test_info.pages_per_vb * _test_info.lba_per_page * _test_info.bytes_per_meta );
_buf.verify_main = WMR_Buf_Alloc_ForDMA(&zone,
_test_info.pages_per_vb * _test_info.bytes_per_page);
_buf.verify_meta = WMR_Buf_Alloc_ForDMA(&zone,
_test_info.pages_per_vb * _test_info.lba_per_page * _test_info.bytes_per_meta);
result = WMR_BufZone_FinishedAllocs(&zone);
WMR_ASSERT(result);
WMR_BufZone_Rebase(&zone, &_buf.write_main);
WMR_BufZone_Rebase(&zone, &_buf.write_meta);
WMR_BufZone_Rebase(&zone, &_buf.verify_main);
WMR_BufZone_Rebase(&zone, &_buf.verify_meta);
WMR_BufZone_FinishedRebases(&zone);
_buf.virtual_page_list = WMR_MALLOC(sizeof(UInt32) * _test_info.pages_per_vb);
WMR_ASSERT(NULL != _buf.virtual_page_list);
result = _RunSequentialTest();
WMR_BufZone_Free(&zone);
WMR_FREE(_buf.virtual_page_list, sizeof(UInt32) * _test_info.pages_per_vb);
return result;
}
////////////////////////////////////////////////////////////////////////////////
// Static function implementations
////////////////////////////////////////////////////////////////////////////////
#if SVFL
static void vfl_read_cb(UInt32 vba, VFLReadStatusType status, UInt8 *meta)
{
if (status & VFL_READ_STATUS_REFRESH) {
WMR_PANIC( "sftl: requested refresh vba:0x%x status:0x%x\n", vba, status);
}
if (status & VFL_READ_STATUS_RETIRE) {
WMR_PANIC("sftl: requested retire vba:0x%x status:0x%x\n", vba, status);
}
if (status & VFL_READ_STATUS_UECC) {
WMR_PANIC("sftl: error uECC vba:0x%x status:0x%x\n", vba, status);
}
if (status & VFL_READ_STATUS_CLEAN) {
WMR_PANIC("sftl: error clean vba:0x%x status:0x%x\n", vba, status);
}
}
#endif // SVFL
BOOL32
_RunSequentialTest
(void)
{
BOOL32 nand_result;
UInt16 block;
const UInt32 TEST_CHUNK_PAGES = _test_info.pages_per_vb;
const UInt32 bytes_per_stripe_main =
TEST_CHUNK_PAGES * _test_info.bytes_per_page;
const UInt32 bytes_per_stripe_meta =
TEST_CHUNK_PAGES * _test_info.lba_per_page * _test_info.bytes_per_meta;
_FillBuffer(_buf.write_main, bytes_per_stripe_main, 0x34);
_FillSwissMetaBuffer(_buf.write_meta, bytes_per_stripe_meta, 0);
WMR_MEMCPY(_buf.verify_main, _buf.write_main, bytes_per_stripe_main);
WMR_MEMCPY(_buf.verify_meta, _buf.write_meta, bytes_per_stripe_meta);
#if(!SVFL) //Vanilla PPNVFL
{
#ifndef AND_READONLY
UInt32 page;
BOOL32 needs_refresh = FALSE32;
WMR_PRINT(ALWAYS,"***************************************Vanilla PPNVFL test starting******************************\n");
for (block = _test_info.num_ftl_vb; block < _test_info.num_total_vb; ++block)
{
Int32 status = FIL_SUCCESS;
const UInt32 first_page_in_vb = block * _test_info.pages_per_vb;
WMR_PRINT(ALWAYS, "Erase block %d(0x%08x)\n", block, block);
status = _vfl->Erase(block, FALSE32);
WMR_ASSERT(VFL_SUCCESS == status);
WMR_PRINT(ALWAYS, "Write pages %d(0x%08x):%d\n",
first_page_in_vb, first_page_in_vb, _test_info.pages_per_vb);
nand_result = _vfl->WriteMultiplePagesInVb(first_page_in_vb,
TEST_CHUNK_PAGES,
_buf.write_main,
_buf.write_meta,
FALSE32,
FALSE32);
WMR_ASSERT(nand_result);
for (page = 0; page < TEST_CHUNK_PAGES; ++page)
{
_buf.virtual_page_list[page] = first_page_in_vb + page;
}
WMR_PRINT(ALWAYS, "Readback pages %d(0x%08x):%d\n",
first_page_in_vb, first_page_in_vb, _test_info.pages_per_vb);
status = _vfl->ReadScatteredPagesInVb(_buf.virtual_page_list,
TEST_CHUNK_PAGES,
_buf.verify_main,
_buf.verify_meta,
&needs_refresh,
NULL,
FALSE32,
NULL);
//WMR_ASSERT(VFL_SUCCESS == status);
WMR_ASSERT(!WMR_MEMCMP(_buf.verify_main, _buf.write_main, bytes_per_stripe_main));
WMR_ASSERT(!WMR_MEMCMP(_buf.verify_meta, _buf.write_meta, bytes_per_stripe_meta));
WMR_ASSERT(!needs_refresh);
}
#endif // !AND_READONLY
// Make another read pass after all programming is complete
for (block = _test_info.num_ftl_vb; block < _test_info.num_total_vb; ++block)
{
const UInt32 first_page_in_vb = block * _test_info.pages_per_vb;
for (page = 0; page < TEST_CHUNK_PAGES; ++page)
{
_buf.virtual_page_list[page] = first_page_in_vb + page;
}
WMR_PRINT(ALWAYS, "Read pages %d(0x%08x):%d\n",
first_page_in_vb, first_page_in_vb, _test_info.pages_per_vb);
nand_result = _vfl->ReadScatteredPagesInVb(_buf.virtual_page_list,
TEST_CHUNK_PAGES,
_buf.verify_main,
_buf.verify_meta,
&needs_refresh,
NULL,
FALSE32,
NULL);
WMR_ASSERT(nand_result);
WMR_ASSERT(!WMR_MEMCMP(_buf.verify_main, _buf.write_main, bytes_per_stripe_main));
WMR_ASSERT(!WMR_MEMCMP(_buf.verify_meta, _buf.write_meta, bytes_per_stripe_meta));
WMR_ASSERT(!needs_refresh);
}
}
#else //SwissVFL
{
UInt32 vba;
WMR_PRINT(ALWAYS,"***************************************SVFL test starting******************************\n");
WMR_PRINT(ALWAYS,"pages_per_vb = %d, lbas_per_page = %d\n",_test_info.pages_per_vb, _test_info.lba_per_page);
WMR_PRINT(ALWAYS,"start blk = %d, end_blk = %d\n",_test_info.num_ftl_vb, _test_info.num_total_vb);
WMR_PRINT(ALWAYS,"bytes_per_meta = %d, buf_write_data: 0x%X, buf_write_meta: 0x%X, buf_read_data: 0x%X, buf_read_meta: 0x%X\n",
_test_info.bytes_per_meta, _buf.write_main, _buf.write_meta, _buf.verify_main, _buf.verify_meta);
//Erase + Program
for (block = _test_info.num_ftl_vb; block < _test_info.num_total_vb; ++block)
{
if(!(_vfl->GetVbasPerVb(block)))
{
continue;
}
Int32 status = FIL_SUCCESS;
const UInt32 first_page_in_vb = block * _test_info.pages_per_vb;
const UInt32 VbasInBlock = _vfl->GetVbasPerVb(block);
WMR_PRINT(ALWAYS, "Erase block %d(0x%08x)\n", block, block);
status = _vfl->Erase(block, FALSE32);
WMR_ASSERT(VFL_SUCCESS == status);
nand_result = _vfl->ProgramMultipleVbas((first_page_in_vb * _test_info.lba_per_page),
VbasInBlock,
_buf.write_main,
_buf.write_meta,
FALSE32,
TRUE32);
WMR_ASSERT(nand_result);
}
//Readback
for (block = _test_info.num_ftl_vb; block < _test_info.num_total_vb; ++block)
{
if(!(_vfl->GetVbasPerVb(block)))
{
continue;
}
const UInt32 start_vba = block * _test_info.pages_per_vb * _test_info.lba_per_page;
const UInt32 end_vba = start_vba + _vfl->GetVbasPerVb(block);
for(vba = start_vba; vba < end_vba; vba++)
{
_vfl->ReadSpansInit(&s, vfl_read_cb, VFL_READ_STATUS_ALL, TRUE32, FALSE32);
_vfl->ReadSpansAdd(&s, vba, 1, _buf.verify_main, _buf.verify_meta);
if(_vfl->ReadSpans(&s) & (VFL_READ_STATUS_UECC | VFL_READ_STATUS_CLEAN))
{
ANDAddressStruct stAddr;
UInt32 dwAddrSize = sizeof(stAddr);
stAddr.dwVpn = vba;
_vfl->GetStruct(AND_STRUCT_VFL_GETADDRESS, &stAddr, &dwAddrSize);
WMR_PANIC("error reading: vba: = 0x%x cs = 0x%x ppn = 0x%x\n", vba, stAddr.dwCS, stAddr.dwPpn);
}
WMR_ASSERT(!WMR_MEMCMP(_buf.verify_main, _buf.write_main, (_test_info.bytes_per_page/_test_info.lba_per_page)));
WMR_ASSERT(!WMR_MEMCMP(_buf.verify_meta, _buf.write_meta, _test_info.bytes_per_meta));
}
}
}
#endif
WMR_PRINT(ALWAYS, "*************************************Test Passed***********************************************\n");
return TRUE32;
}
static void
_FillBuffer
(UInt8 *buffer,
UInt32 size,
UInt8 seed)
{
// Use a counting pattern for now
while (size--)
{
*buffer++ = seed++;
}
}
static void
_FillSwissMetaBuffer
(UInt8 *buffer,
UInt32 size,
UInt8 seed)
{
UInt8 original_seed = seed;
// Use a counting pattern for now
while (size--)
{
*buffer++ = seed++;
if((seed % (_test_info.bytes_per_meta)) == 0 )
{
seed = original_seed;
}
}
}
BOOL32
_GetVFLUInt16
(UInt32 struct_name,
UInt16 *value)
{
UInt32 size = sizeof(*value);
WMR_ASSERT(NULL != value);
*value = 0;
if (!_vfl->GetStruct(struct_name, value, &size) ||
(size != sizeof(*value)))
{
WMR_PRINT(ERROR, "Failed 0x%08x\n", struct_name);
return FALSE32;
}
return TRUE32;
}
BOOL32
_GetVFLUInt32
(UInt32 struct_name,
UInt32 *value)
{
UInt32 size = sizeof(*value);
WMR_ASSERT(NULL != value);
*value = 0;
if (!_vfl->GetStruct(struct_name, value, &size) ||
(size > sizeof(*value)))
{
WMR_PRINT(ERROR, "Failed 0x%08x\n", struct_name);
return FALSE32;
}
return TRUE32;
}
BOOL32
_GetTestInfo
(void)
{
if (!_GetVFLUInt16(AND_STRUCT_VFL_NUM_OF_FTL_SUBLKS,
&_test_info.num_ftl_vb))
{
return FALSE32;
}
if (!_GetVFLUInt16(AND_STRUCT_VFL_NUM_OF_SUBLKS,
&_test_info.num_total_vb))
{
return FALSE32;
}
if (!_GetVFLUInt16(AND_STRUCT_VFL_PAGES_PER_SUBLK,
&_test_info.pages_per_vb))
{
return FALSE32;
}
if (!_GetVFLUInt16(AND_STRUCT_VFL_BYTES_PER_PAGE,
&_test_info.bytes_per_page))
{
return FALSE32;
}
_test_info.lba_per_page = _vfl->GetDeviceInfo(AND_DEVINFO_FIL_LBAS_PER_PAGE);
if (!_GetVFLUInt32(AND_STRUCT_VFL_BYTES_PER_META,
&_test_info.bytes_per_meta))
{
return FALSE32;
}
return TRUE32;
}