first and last commit
This commit is contained in:
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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user