first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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 "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "FPart.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "WhimoryBoot.h"
|
||||
#include "ANDStats.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
static VFLFunctions *stVflFunctions;
|
||||
static FTLFunctions *stFtlFunctions;
|
||||
|
||||
typedef BOOL32 (*GetStructFunc)(UInt32 dwStructType, void * pvoidStructBuffer, UInt32 * pdwStructSize);
|
||||
|
||||
typedef struct {
|
||||
UInt32 dwStructLayer;
|
||||
UInt32 dwStructType;
|
||||
UInt32 dwStructVersion;
|
||||
} ExportStructParameters;
|
||||
|
||||
|
||||
static ExportStructParameters astrStructsToExport[] =
|
||||
{
|
||||
// header (must be first)
|
||||
{ 0, AND_STRUCT_WMR_EXPORT_ALL, AND_EXPORT_STRUCTURE_VERSION},
|
||||
|
||||
// WMR Version (FTL & VFL types)
|
||||
{AND_STRUCT_LAYER_WMR, AND_STRUCT_WMR_VERSION, 0},
|
||||
|
||||
// VFL_type
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_GET_TYPE, 0},
|
||||
|
||||
// FTL_type ( FTL/yaFTL)
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_GET_TYPE, 0},
|
||||
|
||||
// All VFL Meta
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 0, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 1, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 2, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 3, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 4, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 5, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 6, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 7, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 8, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 9, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 10, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 11, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 12, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 13, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 14, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 15, 0},
|
||||
|
||||
//FTL geometry
|
||||
{AND_STRUCT_LAYER_FTL,AND_STRUCT_FTL_GET_FTL_DEVICEINFO, 0},
|
||||
|
||||
// FTL
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_FTLCXT, 0},
|
||||
|
||||
// FTL counters
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_GET_FTL_EC_BINS, 1},
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_GET_FTL_RC_BINS, 1},
|
||||
|
||||
// FTL - Stat
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_STATISTICS, 0},
|
||||
|
||||
// VFL - Stat
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_STATISTICS, 0},
|
||||
|
||||
// FIL - Device Info
|
||||
{AND_STRUCT_LAYER_FIL, AND_STRUCT_FIL_DEVICE_INFO, 0},
|
||||
|
||||
// FIL - Stat
|
||||
{AND_STRUCT_LAYER_FIL, AND_STRUCT_FIL_STATISTICS, 0},
|
||||
|
||||
// footer (must be last)
|
||||
{0, AND_STRUCT_WMR_EXPORT_ALL_END, AND_EXPORT_STRUCTURE_VERSION},
|
||||
|
||||
};
|
||||
|
||||
#define AND_DUMP_DEBUG (0)
|
||||
|
||||
#if AND_DUMP_DEBUG
|
||||
#define DUMP_VAR(variable) WMR_PRINT(ALWAYS, "%s : %u\n", #variable, (UInt32)(variable))
|
||||
|
||||
|
||||
static void
|
||||
hexdump(UInt8 *bytes, int count)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < count; i += 16) {
|
||||
kprintf("%04x:", i);
|
||||
for (j = 0; (j < 16) && ((i + j) < count); j++)
|
||||
kprintf(" %02.2x", *bytes++);
|
||||
kprintf("\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define DUMP_VAR(variable)
|
||||
#endif //AND_DUMP_DEBUG
|
||||
|
||||
|
||||
|
||||
static GetStructFunc _translateStructLayer (UInt32 dwStructLayer)
|
||||
{
|
||||
switch (dwStructLayer)
|
||||
{
|
||||
case AND_STRUCT_LAYER_FTL:
|
||||
return stFtlFunctions->GetStruct;
|
||||
case AND_STRUCT_LAYER_VFL:
|
||||
return stVflFunctions->GetStruct;
|
||||
case AND_STRUCT_LAYER_FIL:
|
||||
return FIL_GetStruct;
|
||||
case AND_STRUCT_LAYER_WMR:
|
||||
return WMR_PPNGetStruct;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static BOOL32 _appendStructToBuffer(void *pvoidExportBuffer,
|
||||
UInt32 *pdwBufferSize,
|
||||
UInt32 dwStructLayer,
|
||||
UInt32 dwStructType,
|
||||
UInt32 dwStructVersion)
|
||||
{
|
||||
UInt32 dwDataSize;
|
||||
BOOL32 boolResult;
|
||||
GetStructFunc fGetStruct = _translateStructLayer(dwStructLayer);
|
||||
UInt8 *cursor = (UInt8*) pvoidExportBuffer;
|
||||
|
||||
|
||||
DUMP_VAR(pvoidExportBuffer);
|
||||
if (pdwBufferSize)
|
||||
{
|
||||
DUMP_VAR(*pdwBufferSize);
|
||||
}
|
||||
DUMP_VAR(dwStructLayer);
|
||||
DUMP_VAR(dwStructType);
|
||||
DUMP_VAR(dwStructVersion);
|
||||
|
||||
if (fGetStruct)
|
||||
{
|
||||
if (pvoidExportBuffer)
|
||||
{
|
||||
// leave room for the struct header
|
||||
cursor += sizeof(ANDExportStruct);
|
||||
}
|
||||
dwDataSize = pdwBufferSize ? (*pdwBufferSize - sizeof(ANDExportStruct)) : 0;
|
||||
boolResult = fGetStruct(dwStructType, cursor, &dwDataSize);
|
||||
DUMP_VAR(dwDataSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for header and footer
|
||||
boolResult = TRUE32;
|
||||
dwDataSize = 0;
|
||||
}
|
||||
|
||||
if (boolResult)
|
||||
{
|
||||
#if AND_DUMP_DEBUG
|
||||
if (pvoidExportBuffer)
|
||||
{
|
||||
hexdump(pvoidExportBuffer, dwDataSize);
|
||||
}
|
||||
#endif
|
||||
if (pdwBufferSize)
|
||||
{
|
||||
*pdwBufferSize = dwDataSize + sizeof(ANDExportStruct);
|
||||
}
|
||||
|
||||
if (pvoidExportBuffer)
|
||||
{
|
||||
ANDExportStruct strExport;
|
||||
|
||||
strExport.dwStructID = dwStructType;
|
||||
strExport.dwStructureVersion = dwStructVersion;
|
||||
strExport.dwDataSize = dwDataSize;
|
||||
strExport.dwIndex = 0; // What is this?
|
||||
|
||||
WMR_MEMCPY(pvoidExportBuffer, &strExport, sizeof(ANDExportStruct));
|
||||
}
|
||||
}
|
||||
else if (pdwBufferSize)
|
||||
{
|
||||
*pdwBufferSize = 0;
|
||||
}
|
||||
|
||||
DUMP_VAR(boolResult);
|
||||
return boolResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define SUB_MIN_ZERO(minuend, subtrahend) (((minuend) > (subtrahend)) ? ((minuend) - (subtrahend)) : 0)
|
||||
|
||||
BOOL32 ANDExportAllStructs(void * pvoidDataBuffer, UInt32 * pdwDataSize)
|
||||
{
|
||||
UInt32 idx;
|
||||
ExportStructParameters *nextStruct;
|
||||
const UInt32 dwNumStructures = sizeof(astrStructsToExport) / sizeof(astrStructsToExport[0]);
|
||||
const UInt32 dwBufferSize = pdwDataSize ? *pdwDataSize : 0;
|
||||
UInt8 *cursor = (UInt8*) pvoidDataBuffer;
|
||||
UInt32 dwBufferRead = 0;
|
||||
UInt32 dwTmpStructSize;
|
||||
|
||||
if (!pdwDataSize)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
// Update globals
|
||||
stVflFunctions = WMR_PPN_GetVFL();
|
||||
stFtlFunctions = WMR_PPN_GetFTL();
|
||||
|
||||
nextStruct = &astrStructsToExport[0];
|
||||
for (idx = 0; idx < dwNumStructures; ++idx)
|
||||
{
|
||||
dwTmpStructSize = SUB_MIN_ZERO(dwBufferSize, dwBufferRead);
|
||||
_appendStructToBuffer(cursor,
|
||||
&dwTmpStructSize,
|
||||
nextStruct->dwStructLayer,
|
||||
nextStruct->dwStructType,
|
||||
nextStruct->dwStructVersion);
|
||||
nextStruct++;
|
||||
if (cursor)
|
||||
{
|
||||
cursor += dwTmpStructSize;
|
||||
}
|
||||
dwBufferRead += dwTmpStructSize;
|
||||
}
|
||||
|
||||
if (pdwDataSize)
|
||||
{
|
||||
*pdwDataSize = dwBufferRead;
|
||||
}
|
||||
|
||||
// pdwDataSize tells the whole story, always pass
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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 "WMRTypes.h"
|
||||
|
||||
#ifndef _ANDSTATS_H_
|
||||
#define _ANDSTATS_H_
|
||||
|
||||
BOOL32 ANDExportAllStructs(void * pvoidDataBuffer, UInt32 * pdwDataSize);
|
||||
|
||||
#endif //_ANDSTATS_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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 "WhimoryBoot.h"
|
||||
#include "WhimoryBootTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
Boot_FTL_Registry_t g_ftl_registry[] =
|
||||
{
|
||||
{ SFTL_PPN_MAJOR_VER, SFTL_PPN_Register },
|
||||
{ YAFTL_PPN_MAJOR_VER, YAFTL_PPN_Register },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
Boot_VFL_Registry_t g_vfl_registry[] =
|
||||
{
|
||||
{ PPN_SVFL_MAJOR_VER, PPN_SVFL_GetFunctions },
|
||||
{ PPN_VFL_MAJOR_VER, PPN_VFL_GetFunctions },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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 "WhimoryBoot.h"
|
||||
#include "WhimoryBootTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
Boot_FTL_Registry_t g_ftl_registry[] =
|
||||
{
|
||||
{ SFTL_PPN_MAJOR_VER, SFTL_PPN_Register },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
Boot_VFL_Registry_t g_vfl_registry[] =
|
||||
{
|
||||
{ PPN_SVFL_MAJOR_VER, PPN_SVFL_GetFunctions },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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 "WhimoryBoot.h"
|
||||
#include "WhimoryBootTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
Boot_FTL_Registry_t g_ftl_registry[] =
|
||||
{
|
||||
{ YAFTL_PPN_MAJOR_VER, YAFTL_PPN_Register },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
Boot_VFL_Registry_t g_vfl_registry[] =
|
||||
{
|
||||
{ PPN_VFL_MAJOR_VER, PPN_VFL_GetFunctions },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,208 @@
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _WHIMORY_BOOT_H_
|
||||
#define _WHIMORY_BOOT_H_
|
||||
|
||||
#include "WMRTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
#include "FPart.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif //__cplusplus
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public structure definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum _WhimoryBootCode
|
||||
{
|
||||
kWhimoryOk = 0,
|
||||
|
||||
kWhimoryWarning = (1 << 29),
|
||||
kWhimoryWarningUnformatted,
|
||||
kWhimoryEpochMismatch_Deprecated,
|
||||
kWhimoryMinorVersionMismatch,
|
||||
kWhimoryMajorVersionNotAvailable,
|
||||
kWhimoryBirthVersionTooNew,
|
||||
|
||||
kWhimoryError = (1 << 30),
|
||||
kWhimoryErrMissingHardware,
|
||||
kWhimoryErrOutOfMemory,
|
||||
kWhimoryErrUnsupportedVersion,
|
||||
kWhimoryErrSetup,
|
||||
kWhimoryErrUnitTestFailed,
|
||||
kWhimoryErrCorruptedFormat,
|
||||
} WhimoryBootCode;
|
||||
|
||||
#define kWhimoryBootOptionLowPower (1 << 0)
|
||||
#define kWhimoryBootOptionForceFtlRecovery (1 << 1)
|
||||
#define kWhimoryBootOptionFreshOffFTLFormat (1 << 2)
|
||||
#define kWhimoryBootOptionDisableGCInTrim (1 << 3)
|
||||
#define kWhimorySetIndexCacheSize (1 << 4)
|
||||
#define kWhimoryBootOptionReadOnly (1 << 16) // Must align with WMR_INIT_OPEN_READONLY @ bit 16.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public function declarations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Start
|
||||
//
|
||||
// WMR_Start will attempt to locate a signature. It will call OAM_Init()
|
||||
// and FIL_Init(), so those fuctions should be idempotent.
|
||||
// Possible non-fatal outcomes:
|
||||
// kWhimoryWarningUnformatted - Run WMR_Initial_Format()
|
||||
//
|
||||
// On kWhimoryOk or warnings, callers can request WMR_PPN_GetFPart()
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Start
|
||||
(UInt32 fpart_major_ver,
|
||||
UInt32 fpart_options,
|
||||
UInt32 boot_options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Open
|
||||
//
|
||||
// WMR_Open will open a block device if the media is properly formatted
|
||||
// and return appropriate warnings if the device needs to be formatted or
|
||||
// repaired.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Open
|
||||
(UInt32 *total_sectors,
|
||||
UInt32 *sector_size,
|
||||
UInt32 *index_cache,
|
||||
UInt32 boot_options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Format
|
||||
//
|
||||
// Format the media with a given set of preferred versions
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Initial_Format
|
||||
(UInt32 fpart_major_ver,
|
||||
UInt32 fpart_options,
|
||||
UInt32 fpart_format_options,
|
||||
UInt32 vfl_major_ver,
|
||||
UInt32 vfl_options,
|
||||
UInt32 ftl_major_ver,
|
||||
UInt32 ftl_options,
|
||||
UInt32 num_keepout_blocks,
|
||||
UInt32 megabytes_for_ftl);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Partition
|
||||
//
|
||||
// Re-size the portion of the VFL that is visible to FTL.
|
||||
// A value of 0 gives the entire media to FTL.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Partition
|
||||
(UInt32 megabytes_for_ftl);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Update
|
||||
//
|
||||
// Update the physical format if newer format is supported by this software.
|
||||
// Optionally require backward compatiblity and saving user data
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Update
|
||||
(const BOOL32 keep_backward_compatibility,
|
||||
const BOOL32 save_data,
|
||||
UInt32 vfl_major_ver,
|
||||
UInt32 vfl_options,
|
||||
UInt32 ftl_major_ver,
|
||||
UInt32 ftl_options,
|
||||
UInt32 num_keepout_blocks);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Close
|
||||
//
|
||||
// Gracefully shut down the block device, deallocate all buffers, and return
|
||||
// static variables to initial state such that WMR_Open can be called again.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
WMR_Close
|
||||
(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_PPN_CtrlIO
|
||||
//
|
||||
// Generic IOCtl interface to all layers of whimory. Caller must specifiy data
|
||||
// buffer size in incoming size pointer.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL32
|
||||
WMR_PPN_CtrlIO
|
||||
(UInt32 ctrlio_type,
|
||||
void *data,
|
||||
UInt32 *size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_PPNGetStruct
|
||||
//
|
||||
// Get a parameter from RAM
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL32
|
||||
WMR_PPNGetStruct
|
||||
(UInt32 ctrlio_type,
|
||||
void *data,
|
||||
UInt32 *size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_PPNGetCurrentSignature
|
||||
//
|
||||
// Get the signature representing the current software state
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const struct WhimorySignature *
|
||||
WMR_PPNGetSignature
|
||||
(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
//
|
||||
// Get a parameter from RAM
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
FTLFunctions *WMR_PPN_GetFTL
|
||||
(void);
|
||||
VFLFunctions *WMR_PPN_GetVFL
|
||||
(void);
|
||||
FPartFunctions *WMR_PPN_GetFPart
|
||||
(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif //_WHIMORY_BOOT_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _WHIMORY_BOOT_TYPES_H_
|
||||
#define _WHIMORY_BOOT_TYPES_H_
|
||||
|
||||
#define WHIMORY_SIGNATURE_SIZE (3 * 512)
|
||||
struct WhimorySignature
|
||||
{
|
||||
UInt32 magic;
|
||||
#define WHIMORY_SIGNATURE_MAGIC (0x776D7278) // 'wmrx'
|
||||
UInt32 _deprecated_epoch; // 0 for new devices
|
||||
UInt32 whimory_ver_at_birth; // SW older than birth epoch may not open this drive
|
||||
#define WHIMORY_SIGNATURE_VER_PPN_CUR (6)
|
||||
UInt32 ftl_major_ver;
|
||||
UInt32 ftl_minor_ver;
|
||||
UInt32 ftl_options;
|
||||
UInt32 vfl_major_ver;
|
||||
UInt32 vfl_minor_ver;
|
||||
UInt32 vfl_options;
|
||||
UInt32 fpart_major_ver;
|
||||
UInt32 fpart_minor_ver;
|
||||
UInt32 fpart_options; // debug-only: need these to find signature
|
||||
UInt32 num_keepout_blocks;
|
||||
|
||||
UInt32 num_chip_enables;
|
||||
|
||||
// Informational
|
||||
#define WHIMORY_SW_VER_MAX_LENGTH (128)
|
||||
UInt8 sw_ver_str[WHIMORY_SW_VER_MAX_LENGTH];
|
||||
UInt32 fpart_format_options; // options used for initial format
|
||||
|
||||
#define WHIMORY_FTL_PARTITION_VALID_BIT (1UL << 31)
|
||||
#define WHIMORY_FTL_PARTITION_SIZE_MASK (0x7fffffffUL)
|
||||
UInt32 megabytes_for_ftl;
|
||||
|
||||
// Reserve to 1.5KB
|
||||
UInt8 reserved[WHIMORY_SIGNATURE_SIZE - (16 * sizeof(UInt32)) - 128];
|
||||
};
|
||||
|
||||
struct WhimoryDeviceInfo
|
||||
{
|
||||
UInt32 num_ce;
|
||||
UInt32 main_bytes_per_page;
|
||||
UInt32 total_meta_per_page;
|
||||
UInt32 lba_per_page;
|
||||
};
|
||||
|
||||
typedef FTLFunctions * (*FTL_Registrar)(void);
|
||||
typedef struct
|
||||
{
|
||||
UInt32 major_ver;
|
||||
FTL_Registrar registrar;
|
||||
} Boot_FTL_Registry_t;
|
||||
|
||||
typedef VFLFunctions * (*VFL_Registrar)(void);
|
||||
typedef struct
|
||||
{
|
||||
UInt32 major_ver;
|
||||
VFL_Registrar registrar;
|
||||
} Boot_VFL_Registry_t;
|
||||
|
||||
typedef FPartFunctions * (*FPart_Registrar)(void);
|
||||
typedef struct
|
||||
{
|
||||
UInt32 major_ver;
|
||||
FPart_Registrar registrar;
|
||||
} Boot_FPart_Registry_t;
|
||||
|
||||
#endif //_WHIMORY_BOOT_TYPES_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,69 @@
|
||||
#ifndef _PPNFPART_TYPES_H_
|
||||
#define _PPNFPART_TYPES_H_
|
||||
|
||||
#include "WMRConfig.h"
|
||||
#include "PPNMiscTypes.h"
|
||||
#include "WMRBufTypes.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#define PPNFPART_MAX_SPECIAL_BLOCKS_PER_TYPE (8)
|
||||
#define PPNFPART_MAX_SPECIAL_BLOCKS_TYPE (20)
|
||||
|
||||
#define PPNFPART_SPECIAL_BLOCK_SPARE_TYPE (AND_SPARE_TYPE_REGION_FPART + 0x00)
|
||||
|
||||
// On NAND structures - Start
|
||||
|
||||
#define PPNFPART_STRUCTURE_VERSION (0x00000001) // use the two MSB as major - not forward compatible
|
||||
|
||||
// SpecialBlockHeaderStruct - used as a header in special blocks that are managed
|
||||
// by PPNFPart
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UInt16 bank;
|
||||
UInt16 block;
|
||||
} block_addresses[PPNFPART_MAX_SPECIAL_BLOCKS_PER_TYPE];
|
||||
UInt32 version;
|
||||
UInt32 data_size;
|
||||
UInt32 copy_number;
|
||||
UInt32 reserved[21]; // reserving bits and rounding the structure size to 128 bytes
|
||||
} SpecialBlockHeaderStruct;
|
||||
|
||||
// PPNFPart_Spare - used in the metadata of any speical blcok
|
||||
// managed by PPNFPart
|
||||
typedef struct
|
||||
{
|
||||
UInt8 spare_type; // spare type
|
||||
UInt8 index; // for spcial blocks holding information that cross page boundary
|
||||
UInt16 vfl_special_type; // shared type (between VFL and FPART) identifying this type of special block
|
||||
UInt8 reserved1[12];
|
||||
} PPNFPart_Spare;
|
||||
|
||||
// On NAND structures - End
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt16 bank;
|
||||
UInt16 block;
|
||||
UInt16 type;
|
||||
} SpecialBlockCacheEntryType;
|
||||
|
||||
/* PPNFPart internal structures */
|
||||
typedef struct
|
||||
{
|
||||
PPN_DeviceInfo dev;
|
||||
LowFuncTbl *fil;
|
||||
SpecialBlockCacheEntryType * special_blocks; // malloc to size AND_MAX_SPECIAL_BLOCKS in init
|
||||
UInt16 special_blocks_idx; // pointer to the next available entry in the special_blocks array
|
||||
BOOL32 done_mapping; // flag indicating the cache is up to date - no need to search in nand
|
||||
|
||||
// reserve a single command struct for fpart to
|
||||
// do physical operations
|
||||
WMR_BufZone_t zone;
|
||||
PPNCommandStruct * command;
|
||||
BOOL32 initialized;
|
||||
} PPNFPart_MainCxt; // hold all other pointers
|
||||
|
||||
#endif /* _PPNFPART_TYPES_H_ */
|
||||
@@ -0,0 +1,97 @@
|
||||
//Test file compiled only for simulator
|
||||
|
||||
static BOOL32
|
||||
ppnMiscTestConversionFunctions
|
||||
(PPN_DeviceInfo * dev);
|
||||
|
||||
static BOOL32
|
||||
_verifyAnAddress
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc)
|
||||
{
|
||||
UInt16 chip_enable_idx, channel, cau;
|
||||
UInt32 page_address = 0, line_failed = 0;
|
||||
UInt16 temp_bank, temp_block, temp_page_offset;
|
||||
BOOL32 temp_slc;
|
||||
|
||||
// convert to a physical address
|
||||
cau = ppnMiscGetCAUFromBank(dev, bank);
|
||||
if (!(cau < dev->caus_per_ce))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
page_address = ppnMiscConvertToPPNPageAddress(dev, cau, block, page_offset, slc);
|
||||
chip_enable_idx = ppnMiscGetCEIdxFromBank(dev, bank);
|
||||
if (!(chip_enable_idx < dev->ces_per_channel))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
channel = ppnMiscGetChannelFromBank(dev, bank);
|
||||
if (!(channel < dev->num_channels))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
// convert back
|
||||
ppnMiscConvertPhysicalAddressToBankBlockPage(dev, channel, chip_enable_idx, page_address,
|
||||
&temp_bank, &temp_block, &temp_page_offset, &temp_slc);
|
||||
if (!((temp_bank == bank) && (temp_block == block) && (temp_page_offset == page_offset) && (slc == temp_slc)))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
|
||||
return_error:
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] fail address conversion: (l:%d)\n"), line_failed));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] bank:0x%X, block:0x%X, page_offset:0x%X, slc:0x%X\n"),
|
||||
bank, block, page_offset, slc));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] channel:0x%X, chip_enable_idx:0x%X, cau:0x%X\n"),
|
||||
channel, chip_enable_idx, cau));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] temp_bank:0x%X, temp_block:0x%X, temp_page_offset:0x%X, temp_slc:0x%X\n"),
|
||||
temp_bank, temp_block, temp_page_offset, temp_slc));
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
static BOOL32
|
||||
ppnMiscTestConversionFunctions
|
||||
(PPN_DeviceInfo * dev)
|
||||
{
|
||||
UInt16 bank, block, page_offset;
|
||||
UInt32 counter = 0;
|
||||
|
||||
for (bank = 0; bank < dev->num_of_banks; bank++)
|
||||
{
|
||||
for (block = 0; block < dev->blocks_per_cau; block++)
|
||||
{
|
||||
for (page_offset = 0; page_offset < dev->pages_per_block_mlc; page_offset++)
|
||||
{
|
||||
counter++;
|
||||
if (!(_verifyAnAddress(dev, bank, block, page_offset, TRUE32)))
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] fail address conversion test: (l:%d)\n"), __LINE__));
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
for (page_offset = 0; page_offset < dev->pages_per_block_slc; page_offset++)
|
||||
{
|
||||
if (!(_verifyAnAddress(dev, bank, block, page_offset, TRUE32)))
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] fail address conversion test: (l:%d)\n"), __LINE__));
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_H__
|
||||
#define __L2V_H__
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern L2V_t L2V;
|
||||
extern UInt8 *L2V_root_depth;
|
||||
|
||||
|
||||
#endif // __L2V_H__
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_CASSERT_H__
|
||||
#define __L2V_CASSERT_H__
|
||||
|
||||
#define l2v_assert(e) WMR_ASSERT(e)
|
||||
|
||||
#define CASSERT(x, name) typedef char __CASSERT_##name[(x) ? 1 : -1]
|
||||
|
||||
#define l2v_assert_le(x, y) l2v_assert((x) <= (y))
|
||||
#define l2v_assert_lt(x, y) l2v_assert((x) < (y))
|
||||
#define l2v_assert_ge(x, y) l2v_assert((x) >= (y))
|
||||
#define l2v_assert_gt(x, y) l2v_assert((x) > (y))
|
||||
#define l2v_assert_eq(x, y) l2v_assert((x) == (y))
|
||||
#define l2v_assert_ne(x, y) l2v_assert((x) != (y))
|
||||
|
||||
#endif // __L2V_CASSERT_H__
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_CONFIG_H__
|
||||
#define __L2V_CONFIG_H__
|
||||
|
||||
// Defines the minium page size--ONLY used for easier extent (logical range) configuration
|
||||
#define L2V_MINPAGESIZE_BITS (b_4 + KiB_bits)
|
||||
|
||||
// Defines the node size
|
||||
#define L2V_CACHELINE 64
|
||||
#define L2V_NODE_SIZE L2V_CACHELINE
|
||||
|
||||
// Defines the memory set aside for the node pool
|
||||
#define L2V_NODEPOOL_MEM (MiB>>2)
|
||||
|
||||
// Defines the size of a logical tree
|
||||
#define L2V_TREE_BITS 15
|
||||
|
||||
// Repack periodicity
|
||||
#define L2V_REPACK_PERIOD 200
|
||||
|
||||
|
||||
#endif // __L2V_CONFIG_H__
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_DEFINES_H__
|
||||
#define __L2V_DEFINES_H__
|
||||
|
||||
// Shortcuts for the config
|
||||
#define b_1 0
|
||||
#define b_2 1
|
||||
#define b_4 2
|
||||
#define b_8 3
|
||||
#define b_16 4
|
||||
#define b_32 5
|
||||
#define b_64 6
|
||||
#define b_128 7
|
||||
#define b_256 8
|
||||
#define b_512 9
|
||||
#define KiB_bits 10
|
||||
#define MiB_bits 20
|
||||
#define GiB_bits 30
|
||||
#define TiB_bits 40
|
||||
#define KiB (1 << KiB_bits)
|
||||
#define MiB (1 << MiB_bits)
|
||||
#define GiB (1 << GiB_bits)
|
||||
#define TiB (1 << TiB_bits)
|
||||
|
||||
#include "L2V_Config.h"
|
||||
|
||||
|
||||
// Pointers to NAND
|
||||
// VPN bits were originally defined seperately as superblock bits, page offset bits;
|
||||
// combining them results in more flexibility. 10+3 was supposed to represent 8192 max superblocks;
|
||||
// 12 represented 4096 max pages per superblock.
|
||||
#define L2V_BITS_VPN (10+3+12)
|
||||
#define L2V_MAX_SB (1 << L2V_BITS_SB)
|
||||
#define L2V_BITS_NAND_SPAN (32 - 2 - L2V_BITS_VPN)
|
||||
|
||||
|
||||
// Node size
|
||||
#define L2V_CONTIG_ELEM_SMALL 4
|
||||
#define L2V_CONTIG_ELEM_LARGE 6
|
||||
#define L2V_MIN_CONTIG_PER_NODE (L2V_NODE_SIZE / L2V_CONTIG_ELEM_LARGE)
|
||||
#define L2V_MAX_CONTIG_PER_NODE (L2V_NODE_SIZE / L2V_CONTIG_ELEM_SMALL)
|
||||
|
||||
|
||||
// Memory usage
|
||||
#define L2V_NODEPOOL_COUNT (L2V_NODEPOOL_MEM / L2V_NODE_SIZE)
|
||||
#define L2V_BITS_NODEIDX 16
|
||||
#define L2V_BITS_NODE_SPAN (32 - 2 - L2V_BITS_NODEIDX)
|
||||
|
||||
|
||||
// Parameters
|
||||
#define L2V_SUCKUP_CHILDREN_MAX 3
|
||||
#define L2V_TRACK_VALID 0
|
||||
|
||||
|
||||
// Tree size
|
||||
#define L2V_TREE_SIZE (1 << L2V_TREE_BITS)
|
||||
#define L2V_TREE_MASK (L2V_TREE_SIZE - 1)
|
||||
#define L2V_MAX_TREE_DEPTH 32
|
||||
#define L2V_MAX_TREE_DEPTH_UPD 36
|
||||
#define L2V_TREE_DEPTH_REPACK 26
|
||||
|
||||
|
||||
// Magic numbers
|
||||
#define L2V_CONTIG_FREE_SIG 0xFFFFFFFF
|
||||
// These represent token values; normally, when we move along a span, we add to vpn and
|
||||
// subtract from span. If it's a token--such as "missing" or "deallocated"--we should
|
||||
// subtract from span, but not add to vpn, because it would change the meaning.
|
||||
#define L2V_VPN_DEALLOC ((1<<L2V_BITS_VPN)-0xfffe)
|
||||
#define L2V_VPN_MISS ((1<<L2V_BITS_VPN)-0xfffd)
|
||||
#define L2V_VPN_SPECIAL L2V_VPN_DEALLOC
|
||||
|
||||
|
||||
// Transforms
|
||||
#define L2V_IDX_TO_NODE(idx) (&L2V.Pool.Node[idx])
|
||||
#define L2V_NODE_TO_IDX(ptr) ((lNode_t*)(ptr) - &L2V.Pool.Node[0])
|
||||
|
||||
// Memory state
|
||||
#define L2V_LowMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*4))
|
||||
|
||||
|
||||
#endif // __L2V_DEFINES_H__
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_EXTERN_H__
|
||||
#define __L2V_EXTERN_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
// Define the context structure for faster macro access
|
||||
extern L2V_t L2V;
|
||||
extern UInt8 *L2V_root_depth;
|
||||
|
||||
extern BOOL32 L2V_Init(UInt32 numLbas, UInt32 numSBs, UInt32 pagesPerSB);
|
||||
extern void L2V_Free(void);
|
||||
extern void L2V_Search_Init(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Search(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
extern void L2V_ForgetBiggestTree(void);
|
||||
|
||||
#define L2V_LowMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*4))
|
||||
|
||||
|
||||
#endif // __L2V_EXTERN_H__
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
#include "L2V_Forget.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
static UInt32 ChooseBiggest(void);
|
||||
static void Forget(lNode_t *node);
|
||||
static void ReplaceRoot(UInt32 tree);
|
||||
|
||||
void L2V_ForgetBiggestTree()
|
||||
{
|
||||
UInt32 tree;
|
||||
|
||||
tree = ChooseBiggest();
|
||||
|
||||
// Trying to repack a rootptr? Abort...
|
||||
if (((UInt32)~0 == tree) || (!LPTR_IS_NODEPTR(L2V.Tree[tree]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Forget(L2V_IDX_TO_NODE(LPTR_GET_NODEIDX(L2V.Tree[tree])));
|
||||
|
||||
ReplaceRoot(tree);
|
||||
}
|
||||
|
||||
static UInt32 ChooseBiggest()
|
||||
{
|
||||
UInt32 i, biggest, biggestSize;
|
||||
|
||||
biggest = ~0;
|
||||
biggestSize = 0;
|
||||
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
if (L2V.TreeNodes[i] > biggestSize) {
|
||||
biggest = i;
|
||||
biggestSize = L2V.TreeNodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return biggest;
|
||||
}
|
||||
|
||||
static void Forget(lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node and size
|
||||
lPtr_t thisPtr;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
// Recurse
|
||||
Forget(L2V_IDX_TO_NODE(cu.u.nodeIdx));
|
||||
}
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
// Free the node
|
||||
_L2V_FreeNode(node);
|
||||
}
|
||||
|
||||
static void ReplaceRoot(UInt32 tree)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Set up contig
|
||||
cu.isNodePtr = 0;
|
||||
cu.hasSpanOF = 0;
|
||||
cu.u.n.vpn = L2V_VPN_MISS;
|
||||
cu.span = 0; // Just so it's consistent... value doesn't matter in root
|
||||
|
||||
// Update tree
|
||||
L2V.Tree[tree] = LPTR_PACK_NAND(cu);
|
||||
L2V.TreeNodes[tree] = 0;
|
||||
L2V_root_depth[tree] = 0;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_FORGET_H__
|
||||
#define __L2V_FORGET_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void L2V_ForgetBiggestTree(void);
|
||||
|
||||
|
||||
#endif // __L2V_FORGET_H__
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 "WMRFeatures.h"
|
||||
#include "L2V_Extern.h"
|
||||
|
||||
#if ENABLE_L2V_TREE
|
||||
|
||||
void L2V_Free(void)
|
||||
{
|
||||
if (0 == L2V.numRoots)
|
||||
return;
|
||||
|
||||
// Free arrays:
|
||||
|
||||
if (NULL != L2V.Tree) {
|
||||
WMR_FREE(L2V.Tree, L2V.numRoots * sizeof(lPtr_t));
|
||||
L2V.Tree = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.TreeNodes) {
|
||||
WMR_FREE(L2V.TreeNodes, L2V.numRoots * sizeof(UInt32));
|
||||
L2V.TreeNodes = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.UpdatesSinceRepack) {
|
||||
WMR_FREE(L2V.UpdatesSinceRepack, L2V.numRoots * sizeof(UInt32));
|
||||
L2V.UpdatesSinceRepack = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.Pool.Node) {
|
||||
WMR_FREE(L2V.Pool.Node, L2V_NODEPOOL_MEM);
|
||||
L2V.Pool.Node = NULL;
|
||||
}
|
||||
|
||||
if(L2V_root_depth != NULL)
|
||||
{
|
||||
WMR_FREE(L2V_root_depth, L2V.numRoots);
|
||||
L2V_root_depth = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
// Empty
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_FUNCS_H__
|
||||
#define __L2V_FUNCS_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
BOOL32 L2V_Init(UInt32 numLbas, UInt32 numSBs, UInt32 pagesPerSB);
|
||||
extern void L2V_Search_Init(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Search(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
extern void L2V_ForgetBiggestTree(void);
|
||||
|
||||
|
||||
// Macros
|
||||
|
||||
#define _L2V_NODE_ITERATE_RESUME(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr) \
|
||||
while ((_nodeByteOfs) <= ((_nodeSize)-sizeof(lPtr_t))) { \
|
||||
(_destPtr) = *(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]); \
|
||||
if (L2V_CONTIG_FREE_SIG == (_destPtr)) { \
|
||||
break; \
|
||||
} \
|
||||
if (LPTR_IS_NODEPTR(_destPtr)) { \
|
||||
LPTR_UNPACK_NODE(_destPtr, _cu); \
|
||||
} else { \
|
||||
LPTR_UNPACK_NAND(_destPtr, _cu); \
|
||||
} \
|
||||
if ((_cu).hasSpanOF) { \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
(_cu).span += *(UInt16*)&(_node)->bytes[_nodeSize] << (LPTR_IS_NODEPTR(_destPtr) ? L2V_BITS_NODE_SPAN : L2V_BITS_NAND_SPAN); \
|
||||
l2v_assert_le(_nodeByteOfs, ((_nodeSize)-sizeof(lPtr_t))); \
|
||||
} \
|
||||
l2v_assert_ne((_cu).span, 0);
|
||||
|
||||
#define _L2V_NODE_ITERATE(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr) \
|
||||
(_nodeByteOfs) = 0; \
|
||||
(_nodeSize) = L2V_NODE_SIZE; \
|
||||
_L2V_NODE_ITERATE_RESUME(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr)
|
||||
|
||||
|
||||
#define _L2V_NODE_ITERATE_NEXT(_nodeByteOfs) \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t);
|
||||
|
||||
#define _L2V_NODE_ITERATE_END_NOP }
|
||||
|
||||
#define _L2V_NODE_ITERATE_END(_nodeByteOfs) \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
}
|
||||
|
||||
#define _L2V_NODE_PUSH_CONTIG_NODE(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
{ \
|
||||
l2v_assert_ne((_cu).span, 0); \
|
||||
(_cu).hasSpanOF = 1; \
|
||||
*(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]) = LPTR_PACK_NODE(_cu); \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
*(UInt16*)&(_node)->bytes[_nodeSize] = (_cu).span >> L2V_BITS_NODE_SPAN; \
|
||||
}
|
||||
#define _L2V_NODE_PUSH_CONTIG_NAND(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
{ \
|
||||
l2v_assert_ne((_cu).span, 0); \
|
||||
(_cu).hasSpanOF = 0; \
|
||||
if ((_cu).span >= (1 << L2V_BITS_NAND_SPAN)) { \
|
||||
(_cu).hasSpanOF = 1; \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
*(UInt16*)&(_node)->bytes[_nodeSize] = (_cu).span >> L2V_BITS_NAND_SPAN; \
|
||||
} \
|
||||
*(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]) = LPTR_PACK_NAND(_cu); \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
}
|
||||
#define _L2V_NODE_PUSH_CONTIG(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
do { \
|
||||
if ((_cu).isNodePtr) { \
|
||||
_L2V_NODE_PUSH_CONTIG_NODE(_node, _nodeByteOfs, _nodeSize, _cu); \
|
||||
} else { \
|
||||
_L2V_NODE_PUSH_CONTIG_NAND(_node, _nodeByteOfs, _nodeSize, _cu); \
|
||||
} \
|
||||
} while (0)
|
||||
#define _L2V_CONTIG_SIZE(_cu) (sizeof(lPtr_t) + (((_cu).isNodePtr || ((_cu).span >= (1 << L2V_BITS_NAND_SPAN))) ? sizeof(UInt16) : 0))
|
||||
|
||||
#define _L2V_NODE_FILL(_node, _nodeByteOfs, _nodeSize) \
|
||||
do { \
|
||||
WMR_MEMSET(&(_node)->bytes[_nodeByteOfs], 0xFF, (_nodeSize) - (_nodeByteOfs)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __L2V_FUNCS_H__
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Mem.h"
|
||||
|
||||
|
||||
// Declare our L2V context structure here
|
||||
L2V_t L2V;
|
||||
UInt8 *L2V_root_depth;
|
||||
|
||||
// Functions
|
||||
BOOL32 L2V_Init(UInt32 numLbas, UInt32 numSBs, UInt32 pagesPerSB)
|
||||
{
|
||||
UInt32 i;
|
||||
Int32 j;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Set number of superblocks for valid accounting division
|
||||
L2V.numSBs = numSBs;
|
||||
L2V.pagesPerSB = pagesPerSB;
|
||||
if ((numSBs * pagesPerSB) >= L2V_VPN_SPECIAL) {
|
||||
WMR_PANIC("Tree bitspace not sufficient for geometry %dx%d: please re-adjust", numSBs, pagesPerSB);
|
||||
}
|
||||
|
||||
// Set tree version
|
||||
L2V.treeVersion = 0;
|
||||
|
||||
// Calculate roots
|
||||
L2V.numRoots = (numLbas >> L2V_TREE_BITS) + 1;
|
||||
|
||||
// Allocate arrays
|
||||
L2V.Tree = WMR_MALLOC(L2V.numRoots * sizeof(lPtr_t));
|
||||
l2v_assert_ne(L2V.Tree, NULL);
|
||||
L2V.TreeNodes = WMR_MALLOC(L2V.numRoots * sizeof(UInt32));
|
||||
l2v_assert_ne(L2V.TreeNodes, NULL);
|
||||
L2V.UpdatesSinceRepack = WMR_MALLOC(L2V.numRoots * sizeof(UInt32));
|
||||
l2v_assert_ne(L2V.UpdatesSinceRepack, NULL);
|
||||
L2V_root_depth = WMR_MALLOC(L2V.numRoots);
|
||||
l2v_assert_ne(L2V_root_depth , NULL);
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
L2V_root_depth[i] = 0;
|
||||
}
|
||||
|
||||
// Empty roots; default to miss
|
||||
cu.hasSpanOF = 0;
|
||||
cu.u.n.vpn = L2V_VPN_MISS;
|
||||
cu.span = 0;
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
L2V.Tree[i] = LPTR_PACK_NAND(cu);
|
||||
}
|
||||
|
||||
// Reset periodic repacker variables
|
||||
L2V.RepackCounter = 0;
|
||||
|
||||
// Allocate the node pool
|
||||
L2V.Pool.Node = (lNode_t*)WMR_MALLOC(L2V_NODEPOOL_MEM);
|
||||
if (NULL == L2V.Pool.Node) {
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
// Finally, put all nodes in the free pool
|
||||
L2V.Pool.FreePtr = NULL;
|
||||
L2V.Pool.FreeCount = 0;
|
||||
for (j = L2V_NODEPOOL_COUNT-1; j >= 0; j--) {
|
||||
_L2V_FreeNode(&L2V.Pool.Node[j]);
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
|
||||
void _L2V_FreeNode(lNode_t *node)
|
||||
{
|
||||
static int freeCount = 0;
|
||||
|
||||
freeCount++;
|
||||
|
||||
l2v_assert_ge(node, &L2V.Pool.Node[0]);
|
||||
l2v_assert_le(node, &L2V.Pool.Node[L2V_NODEPOOL_COUNT]);
|
||||
|
||||
node->nextFreePtr = L2V.Pool.FreePtr;
|
||||
L2V.Pool.FreePtr = node;
|
||||
L2V.Pool.FreeCount++;
|
||||
}
|
||||
|
||||
|
||||
lNode_t *_L2V_AllocNode()
|
||||
{
|
||||
lNode_t *ret;
|
||||
static int allocCount = 0;
|
||||
|
||||
allocCount++;
|
||||
|
||||
ret = (lNode_t*)L2V.Pool.FreePtr;
|
||||
if (NULL != ret) {
|
||||
L2V.Pool.FreePtr = L2V.Pool.FreePtr->nextFreePtr;
|
||||
L2V.Pool.FreeCount--;
|
||||
}
|
||||
l2v_assert_ne(ret, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_MEM_H__
|
||||
#define __L2V_MEM_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void _L2V_FreeNode(lNode_t *node);
|
||||
extern lNode_t *_L2V_AllocNode(void); // Warning: may return NULL; up to caller to handle gracefully
|
||||
|
||||
|
||||
#endif // __L2V_MEM_H__
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Print.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V.h"
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
#define PRINT_MAXPATH 0
|
||||
|
||||
|
||||
// Prototypes
|
||||
|
||||
static int L2V_GetUsage(lNode_t *node, UInt32 *used, UInt32 *total, UInt32 *nodes, UInt32 totalSpan, BOOL32 isMax);
|
||||
|
||||
|
||||
// Functions
|
||||
|
||||
void L2V_PrintPtr(lPtr_t lptr)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
LPTR_UNPACK(lptr, cu);
|
||||
L2V_PrintCU(&cu);
|
||||
}
|
||||
|
||||
void L2V_PrintCU(ContigUnpacked_t *cu)
|
||||
{
|
||||
if (cu->isNodePtr)
|
||||
printf("[Node]");
|
||||
else
|
||||
printf("[NAND]");
|
||||
|
||||
if (cu->hasSpanOF)
|
||||
printf("o");
|
||||
else
|
||||
printf("-");
|
||||
|
||||
if (cu->isNodePtr) {
|
||||
printf("[idx:%d][span:%d]", cu->u.nodeIdx, cu->span);
|
||||
} else {
|
||||
printf("[vpn:%d][span:%d]", cu->u.n.vpn, cu->span);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void L2V_PrintNode(lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize;
|
||||
lPtr_t thisPtr;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
L2V_PrintCU(&cu);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
}
|
||||
|
||||
|
||||
void L2V_PrintUsage(UInt32 tree)
|
||||
{
|
||||
UInt32 used, total, nodes, maxdepth;
|
||||
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
used = total = nodes = maxdepth = 0;
|
||||
printf("Max depth path: ");
|
||||
printf("digraph G {\n");
|
||||
LPTR_UNPACK(L2V.Tree[tree], cu);
|
||||
if (cu.isNodePtr) {
|
||||
maxdepth = L2V_GetUsage(L2V_IDX_TO_NODE(cu.u.nodeIdx), &used, &total, &nodes, L2V_TREE_SIZE, 1);
|
||||
}
|
||||
printf("}\n");
|
||||
printf("\nUsage tree %d: %.2f, nodes: %d, maxdepth: %d\n", tree, (float)used/(float)total, nodes, maxdepth);
|
||||
printf("Nodes calc: %d tally: %d\n\n", nodes, L2V.TreeNodes[tree]);
|
||||
if (nodes != L2V.TreeNodes[tree]) while(1);//DP
|
||||
//l2v_assert_eq(nodes, L2V_NODEPOOL_COUNT - L2V.Pool.FreeCount); // Only valid when using 1 tree
|
||||
}
|
||||
|
||||
static int L2V_GetUsage(lNode_t *node, UInt32 *used, UInt32 *total, UInt32 *nodes, UInt32 totalSpan, BOOL32 isMax)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
UInt32 sumSpan;
|
||||
lPtr_t thisPtr, maxNode;
|
||||
UInt32 depth, maxDepth, maxSpan;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Walk through
|
||||
(*nodes)++;
|
||||
maxDepth = 0;
|
||||
sumSpan = 0;
|
||||
|
||||
// Iterate through the node,
|
||||
L2V_PrintNode(node);
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
printf("%d -> %d;\n", (int)L2V_NODE_TO_IDX(node), cu.u.nodeIdx); // DOT output
|
||||
l2v_assert_ne(cu.u.nodeIdx, 65535);
|
||||
l2v_assert_ne(L2V_IDX_TO_NODE(cu.u.nodeIdx), node);
|
||||
l2v_assert_ne(cu.span, 0);
|
||||
depth = L2V_GetUsage(L2V_IDX_TO_NODE(cu.u.nodeIdx), used, total, nodes, cu.span, 0);
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
maxNode = thisPtr;
|
||||
maxSpan = cu.span;
|
||||
}
|
||||
}
|
||||
sumSpan += cu.span;
|
||||
l2v_assert_le(cu.span, 32768);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
*used += nOfs;
|
||||
*total += sizeof(lNode_t);
|
||||
printf("%d [label=\"us:%.2f\\nsp:%.2f\",shape=box,style=filled,color=\"1.0 %.2f 1.0\"];\n", (int)L2V_NODE_TO_IDX(node), (float)nOfs/sizeof(lNode_t), (float)totalSpan/L2V_TREE_SIZE, (float)nOfs/sizeof(lNode_t)); // DOT output
|
||||
|
||||
if (sumSpan != totalSpan) {
|
||||
printf("Sum: %d, total: %d\n", sumSpan, totalSpan);
|
||||
L2V_PrintNode(node);
|
||||
}
|
||||
l2v_assert_eq(sumSpan, totalSpan);
|
||||
l2v_assert_ne(nOfs, 0);
|
||||
|
||||
#if PRINT_MAXPATH
|
||||
if (maxDepth && isMax) {
|
||||
printf("<-%d", maxNode.node.nodeIdx);
|
||||
L2V_GetUsage(L2V_LPTR_TO_NODE(maxNode), &nOfs, &nOfs, &nOfs, maxSpan, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return maxDepth+1;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_PRINT_H__
|
||||
#define __L2V_PRINT_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void L2V_PrintPtr(lPtr_t lptr);
|
||||
extern void L2V_PrintCU(ContigUnpacked_t *cu);
|
||||
extern void L2V_PrintNode(lNode_t *node);
|
||||
extern void L2V_PrintUsage(UInt32 tree);
|
||||
|
||||
|
||||
#endif // __L2V_PRINT_H__
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#define AND_TRACE_LAYER FTL
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Repack.h"
|
||||
#include "L2V.h"
|
||||
#include "L2V_Types.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
|
||||
#define REPACK_MAX_NODES (L2V_TREE_SIZE/L2V_MIN_CONTIG_PER_NODE)
|
||||
#define REPACK_TREE_LOG_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
lNode_t *bottom[REPACK_MAX_NODES];
|
||||
UInt32 bottomSpan[REPACK_MAX_NODES];
|
||||
UInt32 bottomIdx;
|
||||
UInt32 bottom_nOfs;
|
||||
UInt32 bottom_nodeSize;
|
||||
UInt32 repackTreeLog[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 repackTreeLogIdx;
|
||||
} RepackCtx_t;
|
||||
|
||||
|
||||
// Static definitions
|
||||
static void CopyAndDestroy(RepackCtx_t *r, lNode_t *node);
|
||||
static int Rebuild(RepackCtx_t *r);
|
||||
static void ReplaceRoot(RepackCtx_t *r, UInt32 tree);
|
||||
|
||||
|
||||
void L2V_PeriodicRepack()
|
||||
{
|
||||
Int32 best;
|
||||
UInt32 merit, bestMerit, i;
|
||||
|
||||
// Check if it's appropriate or not
|
||||
if (L2V.RepackCounter < L2V_REPACK_PERIOD) {
|
||||
return;
|
||||
}
|
||||
L2V.RepackCounter = 0;
|
||||
|
||||
// Find best candidate; merit==updates
|
||||
bestMerit = 0;
|
||||
best = -1;
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
merit = L2V.UpdatesSinceRepack[i];
|
||||
if (merit >= bestMerit) {
|
||||
bestMerit = merit;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
l2v_assert_ne(best, -1);
|
||||
|
||||
L2V_Repack(best);
|
||||
}
|
||||
|
||||
|
||||
// WARNING: NOT REENTRANT
|
||||
static RepackCtx_t r;
|
||||
void L2V_Repack(UInt32 tree)
|
||||
{
|
||||
lNode_t *root;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
LPTR_UNPACK(L2V.Tree[tree], cu);
|
||||
|
||||
// Trying to repack a rootptr? Abort...
|
||||
if (!cu.isNodePtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
WMR_TRACE_1(Repack, START, tree);
|
||||
|
||||
// Up tree version for search-update coherency
|
||||
L2V.treeVersion++;
|
||||
|
||||
// Create list of new bottom layer
|
||||
r.bottomIdx = 0;
|
||||
r.bottom_nOfs = 0;
|
||||
r.bottom_nodeSize = L2V_NODE_SIZE;
|
||||
WMR_MEMSET(r.bottom, 0, REPACK_MAX_NODES * sizeof(r.bottom[0]));
|
||||
WMR_MEMSET(r.bottomSpan, 0, REPACK_MAX_NODES * sizeof(r.bottomSpan[0]));
|
||||
|
||||
// Recurse and destroy
|
||||
root = L2V_IDX_TO_NODE(cu.u.nodeIdx);
|
||||
CopyAndDestroy(&r, root);
|
||||
|
||||
l2v_assert_ne(r.bottom_nOfs, 0);
|
||||
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(r.bottom[r.bottomIdx], r.bottom_nOfs, r.bottom_nodeSize);
|
||||
|
||||
// Rebuild hierarchy
|
||||
L2V.TreeNodes[tree] = Rebuild(&r);
|
||||
|
||||
// Replace root
|
||||
ReplaceRoot(&r, tree);
|
||||
|
||||
// Clear repack counter
|
||||
L2V.UpdatesSinceRepack[tree] = 0;
|
||||
|
||||
|
||||
// Log which tree we repacked
|
||||
if (r.repackTreeLogIdx >= REPACK_TREE_LOG_SIZE) {
|
||||
r.repackTreeLogIdx = 0;
|
||||
}
|
||||
r.repackTreeLog[r.repackTreeLogIdx] = tree;
|
||||
r.repackTreeLogIdx++;
|
||||
|
||||
WMR_TRACE_0(Repack, END);
|
||||
}
|
||||
|
||||
|
||||
static void CopyAndDestroy(RepackCtx_t *r, lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
// Recurse
|
||||
CopyAndDestroy(r, L2V_IDX_TO_NODE(cu.u.nodeIdx));
|
||||
} else {
|
||||
// Would be full? Move along...
|
||||
if ((r->bottom_nOfs + _L2V_CONTIG_SIZE(cu)) > r->bottom_nodeSize) {
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(r->bottom[r->bottomIdx], r->bottom_nOfs, r->bottom_nodeSize);
|
||||
|
||||
r->bottomIdx++;
|
||||
l2v_assert_lt(r->bottomIdx, REPACK_MAX_NODES);
|
||||
}
|
||||
|
||||
// Allocate node if necessary
|
||||
if (NULL == r->bottom[r->bottomIdx]) {
|
||||
// Allocate...
|
||||
r->bottom[r->bottomIdx] = _L2V_AllocNode();
|
||||
r->bottom_nOfs = 0;
|
||||
r->bottom_nodeSize = L2V_NODE_SIZE;
|
||||
}
|
||||
|
||||
// Copy out
|
||||
_L2V_NODE_PUSH_CONTIG(r->bottom[r->bottomIdx], r->bottom_nOfs, r->bottom_nodeSize, cu);
|
||||
r->bottomSpan[r->bottomIdx] += cu.span;
|
||||
l2v_assert_le(cu.span, L2V_TREE_SIZE);
|
||||
}
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
// Free the node
|
||||
_L2V_FreeNode(node);
|
||||
}
|
||||
|
||||
|
||||
static int Rebuild(RepackCtx_t *r)
|
||||
{
|
||||
lNode_t *thisBranch;
|
||||
UInt32 nOfs, nodeSize, thisSpan, i, branchIdx;
|
||||
ContigUnpacked_t cu;
|
||||
int nodeCount;
|
||||
|
||||
nodeCount = r->bottomIdx+1;
|
||||
while (r->bottomIdx > 0) {
|
||||
thisBranch = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
nOfs = 0;
|
||||
nodeSize = L2V_NODE_SIZE;
|
||||
thisSpan = 0;
|
||||
branchIdx = 0;
|
||||
|
||||
// Rebuild this layer
|
||||
for (i = 0; i <= r->bottomIdx; i++) {
|
||||
cu.isNodePtr = 1;
|
||||
cu.u.nodeIdx = L2V_NODE_TO_IDX(r->bottom[i]);
|
||||
cu.span = r->bottomSpan[i];
|
||||
|
||||
if ((nOfs + _L2V_CONTIG_SIZE(cu)) > nodeSize) {
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(thisBranch, nOfs, nodeSize);
|
||||
|
||||
// Place it down and get a new one
|
||||
r->bottom[branchIdx] = thisBranch;
|
||||
r->bottomSpan[branchIdx] = thisSpan;
|
||||
branchIdx++;
|
||||
thisBranch = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
nOfs = 0;
|
||||
nodeSize = L2V_NODE_SIZE;
|
||||
thisSpan = 0;
|
||||
}
|
||||
|
||||
_L2V_NODE_PUSH_CONTIG(thisBranch, nOfs, nodeSize, cu);
|
||||
thisSpan += cu.span;
|
||||
}
|
||||
|
||||
l2v_assert_ne(nOfs, 0);
|
||||
|
||||
r->bottom[branchIdx] = thisBranch;
|
||||
r->bottomSpan[branchIdx] = thisSpan;
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(thisBranch, nOfs, nodeSize);
|
||||
|
||||
// Make sure the repack didn't munge the root node's spans
|
||||
if (0 == branchIdx) {
|
||||
l2v_assert_eq(thisSpan, L2V_TREE_SIZE);
|
||||
}
|
||||
|
||||
// Get ready for the next round
|
||||
r->bottomIdx = branchIdx;
|
||||
}
|
||||
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
|
||||
static void ReplaceRoot(RepackCtx_t *r, UInt32 tree)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
l2v_assert_eq(r->bottomIdx, 0);
|
||||
cu.u.nodeIdx = L2V_NODE_TO_IDX(r->bottom[0]);
|
||||
cu.hasSpanOF = 0;
|
||||
cu.span = 0;
|
||||
L2V.Tree[tree] = LPTR_PACK_NODE(cu);
|
||||
if (!LPTR_IS_NODEPTR(L2V.Tree[tree])) {
|
||||
L2V_root_depth[tree] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_REPACK_H__
|
||||
#define __L2V_REPACK_H__
|
||||
|
||||
|
||||
#include "WMROAM.h"
|
||||
|
||||
// Functions
|
||||
|
||||
extern void L2V_PeriodicRepack(void);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
|
||||
|
||||
#endif // __L2V_REPACK_H__
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
|
||||
void L2V_Search_Init(L2V_SearchCtx_t *c)
|
||||
{
|
||||
c->next_lba = 0xffffffff;
|
||||
c->last_node = NULL;
|
||||
c->span = 0;
|
||||
}
|
||||
|
||||
|
||||
static BOOL32 HitCache(L2V_SearchCtx_t *c)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
|
||||
if ((c->treeVersion == L2V.treeVersion) && (c->lba == c->next_lba) && (NULL != c->last_node)) {
|
||||
// Sequential HIT
|
||||
_L2V_NODE_ITERATE_RESUME(c->last_node, c->next_nOfs, c->nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr)
|
||||
break;
|
||||
|
||||
c->vpn = cu.u.n.vpn;
|
||||
c->fromStart = 0;
|
||||
c->span = cu.span;
|
||||
|
||||
_L2V_NODE_ITERATE_NEXT(c->next_nOfs); // This will move nOfs along
|
||||
c->next_lba = c->lba + c->span;
|
||||
return TRUE32;
|
||||
|
||||
} _L2V_NODE_ITERATE_END_NOP;
|
||||
}
|
||||
|
||||
// Clear search history
|
||||
c->next_lba = 0xffffffff;
|
||||
c->last_node = NULL;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
void L2V_Search(L2V_SearchCtx_t *c)
|
||||
{
|
||||
UInt32 targTree, targTofs;
|
||||
UInt32 thisStart, thisMax;
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node, and node effective size
|
||||
ContigUnpacked_t cu, thiscu;
|
||||
lNode_t *node = NULL;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
if (HitCache(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine first root
|
||||
targTree = c->lba >> L2V_TREE_BITS;
|
||||
targTofs = c->lba & L2V_TREE_MASK;
|
||||
l2v_assert_lt(targTree, L2V.numRoots);
|
||||
|
||||
c->level = 0;
|
||||
thisStart = 0;
|
||||
c->vpn = L2V_VPN_MISS;
|
||||
LPTR_UNPACK(L2V.Tree[targTree], cu);
|
||||
thiscu.span = L2V_TREE_SIZE;
|
||||
c->next_nOfs = 0;
|
||||
|
||||
// Search from top down
|
||||
while (c->level < L2V_MAX_TREE_DEPTH) {
|
||||
// Down and next
|
||||
// Decode node pointer
|
||||
if (!cu.isNodePtr) {
|
||||
// Terminal case--pointer to physical location; calculate relative offset...
|
||||
c->vpn = cu.u.n.vpn;
|
||||
c->fromStart = targTofs - thisStart;
|
||||
if (cu.u.n.vpn < L2V_VPN_SPECIAL) {
|
||||
c->vpn += c->fromStart;
|
||||
}
|
||||
c->span = thiscu.span - c->fromStart;
|
||||
// Set up return case for sequential searching
|
||||
c->last_node = node;
|
||||
c->next_lba = c->lba + c->span;
|
||||
c->treeVersion = L2V.treeVersion;
|
||||
// c->next_nOfs is populated from code below, i.e. the previous iteration of this while loop
|
||||
|
||||
// Is it getting really big? Do some preventative maintenence...
|
||||
if (c->level >= L2V_TREE_DEPTH_REPACK) {
|
||||
L2V_Repack(targTree);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk through
|
||||
node = L2V_IDX_TO_NODE(cu.u.nodeIdx);
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, thiscu, thisPtr) {
|
||||
// Calculate endpoint
|
||||
thisMax = thisStart + thiscu.span;
|
||||
|
||||
// Are we in range?
|
||||
if (targTofs < thisMax) {
|
||||
// HIT! (Left-hand side implied by order of search.)
|
||||
cu = thiscu;
|
||||
_L2V_NODE_ITERATE_NEXT(nOfs);
|
||||
c->next_nOfs = nOfs;
|
||||
c->nodeSize = nodeSize;
|
||||
goto decodePtr;
|
||||
}
|
||||
|
||||
// Move along in the node
|
||||
thisStart = thisMax;
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
WMR_PANIC("NAND index: bad tree: targTofs %d, level %d\n", targTofs, c->level);
|
||||
|
||||
decodePtr:
|
||||
// Resume here so we can check the while() condition
|
||||
c->level++;
|
||||
}
|
||||
|
||||
l2v_assert(0); // Should never get here; otherwise, the tree is too deep (or recursive or pointing to randomness)
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Print.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
L2V_t L2V;
|
||||
|
||||
|
||||
#define LAST_TREE_TEST 16
|
||||
#define SIMPLE_SIZE (L2V_TREE_SIZE*LAST_TREE_TEST)
|
||||
|
||||
|
||||
// Prototypes
|
||||
static void RandomTest(void);
|
||||
static void SequentialTest(void);
|
||||
static void Simple_Init(void);
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vpn);
|
||||
|
||||
void Usage(int argc, char** argv)
|
||||
{
|
||||
printf("Usage: %s s OR %s r (for sequential and random, respectively\n", argv[0], argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int test = 0;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
L2V_Init(SIMPLE_SIZE, (L2V_VPN_SPECIAL-1) / 8192, 8192);
|
||||
|
||||
if (argc == 2) {
|
||||
if ('r' == argv[1][0]) {
|
||||
test = 0;
|
||||
} else if ('s' == argv[1][0]) {
|
||||
test = 1;
|
||||
} else {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
}
|
||||
if (argc > 2) {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
|
||||
if (0 == test) {
|
||||
RandomTest();
|
||||
} else {
|
||||
SequentialTest();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define MAXLEN 512
|
||||
static void RandomTest() {
|
||||
UInt32 lba, size, vpn;
|
||||
UInt32 i, svpn;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
sranddev();
|
||||
|
||||
while (1) {
|
||||
lba = rand() % ((L2V_TREE_SIZE*LAST_TREE_TEST)-MAXLEN);
|
||||
size = (rand() % (MAXLEN-1))+1;
|
||||
vpn = rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vpn:%d]\n", lba, size, vpn);
|
||||
L2V_Update(lba, size, vpn);
|
||||
Simple_Update(lba, size, vpn);
|
||||
//printf("\n");
|
||||
//L2V_PrintNode(L2V_LPTR_TO_NODE(L2V.Tree[0]));
|
||||
L2V_PrintUsage(0);
|
||||
|
||||
|
||||
// Validate entire range
|
||||
int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svpn);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svpn != c.vpn) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vpn:%d\n", svpn);
|
||||
printf("Lookup vpn:%d\n", c.vpn);
|
||||
}
|
||||
l2v_assert_eq(svpn, c.vpn);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
|
||||
#if 0
|
||||
if (repack++ > 10) {
|
||||
printf("Repacking tree %d...\n", nextRepack);
|
||||
L2V_Repack(nextRepack);
|
||||
L2V_PrintUsage(nextRepack);
|
||||
repack = 0;
|
||||
nextRepack = (nextRepack + 1) % LAST_TREE_TEST;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void SequentialTest() {
|
||||
UInt32 lba, size, vpn;
|
||||
UInt32 i, svpn;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
sranddev();
|
||||
|
||||
lba = 0;
|
||||
size = 0;
|
||||
vpn = 1;
|
||||
|
||||
while (1) {
|
||||
lba += size;
|
||||
size = (rand() % (MAXLEN-1))+1;
|
||||
if ((lba + size) >= L2V_TREE_SIZE) {
|
||||
lba = 0;
|
||||
}
|
||||
if ((rand() & 3) == 0) {
|
||||
vpn = rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
}
|
||||
while (((vpn + size) & ((1<<(L2V_BITS_VPN-1))-1)) < vpn) {
|
||||
vpn = rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
}
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vpn:%d]\n", lba, size, vpn);
|
||||
L2V_Update(lba, size, vpn);
|
||||
Simple_Update(lba, size, vpn);
|
||||
L2V_PrintUsage(0);
|
||||
vpn += size;
|
||||
|
||||
|
||||
// Validate entire range
|
||||
int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svpn);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svpn != c.vpn) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vpn:%d\n", svpn);
|
||||
printf("Lookup vpn:%d\n", c.vpn);
|
||||
}
|
||||
l2v_assert_eq(svpn, c.vpn);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 Simple_vpn[SIMPLE_SIZE];
|
||||
|
||||
static void Simple_Init()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_vpn[i] = L2V_VPN_MISS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vpn)
|
||||
{
|
||||
while (size) {
|
||||
Simple_vpn[lba] = vpn;
|
||||
|
||||
// Iterate
|
||||
lba++;
|
||||
if (vpn < L2V_VPN_SPECIAL) {
|
||||
vpn++;
|
||||
}
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vpn)
|
||||
{
|
||||
*vpn = Simple_vpn[lba];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
OBJS=L2V_Test.o L2V_Funcs.o L2V_Init.o L2V_Mem.o L2V_Search.o L2V_Update.o L2V_Valid.o L2V_Types.o L2V_Print.o L2V_Repack.o L2V_Forget.o L2V_Free.o WMROAM.o
|
||||
LINK_TARGET=L2V_Test
|
||||
REBUILDABLES=$(OBJS) $(LINK_TARGET)
|
||||
|
||||
.PHONY: all
|
||||
all: copythem $(LINK_TARGET) cleanthem
|
||||
#
|
||||
|
||||
.PHONY: copythem
|
||||
copythem:
|
||||
cp WMROAM-test.h WMROAM.h
|
||||
cp WMROAM-test.c WMROAM.c
|
||||
cp WMRFeatures-test.h WMRFeatures.h
|
||||
|
||||
.PHONY: cleanthem
|
||||
cleanthem:
|
||||
rm WMROAM.c WMROAM.h WMRFeatures.h
|
||||
|
||||
$(LINK_TARGET): $(OBJS)
|
||||
gcc -g -o $@ $^ -Wall
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(REBUILDABLES)
|
||||
rm WMROAM.c WMROAM.h WMRFeatures.h
|
||||
|
||||
%.o: %.c
|
||||
gcc -g -o $@ -c $< -Wall -I.
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Defines.h"
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig(lNodeBig_t *big, ContigUnpacked_t *cu)
|
||||
{
|
||||
Int32 last = ((Int32)big->max)-1;
|
||||
l2v_assert_ne(cu->span, 0);
|
||||
|
||||
if (!cu->isNodePtr && (last >= 0) && !big->cu[last].isNodePtr && (
|
||||
((cu->u.n.vpn < L2V_VPN_SPECIAL) && ((big->cu[last].u.n.vpn+big->cu[last].span) == cu->u.n.vpn))
|
||||
|| ((cu->u.n.vpn >= L2V_VPN_SPECIAL) && (big->cu[last].u.n.vpn == cu->u.n.vpn))))
|
||||
{
|
||||
big->cu[last].span += cu->span;
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
big->cu[big->max] = *cu;
|
||||
big->max++;
|
||||
|
||||
if (cu->isNodePtr) {
|
||||
l2v_assert_lt(cu->u.nodeIdx, L2V_NODEPOOL_COUNT);
|
||||
}
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig_Node(lNodeBig_t *big, UInt32 nodeIdx, UInt32 span)
|
||||
{
|
||||
big->cu[big->max].isNodePtr = 1;
|
||||
big->cu[big->max].u.nodeIdx = nodeIdx;
|
||||
big->cu[big->max].span = span;
|
||||
big->max++;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig_Nand(lNodeBig_t *big, UInt32 vpn, UInt32 span)
|
||||
{
|
||||
Int32 last = ((Int32)big->max)-1;
|
||||
l2v_assert_ne(span, 0);
|
||||
|
||||
if ((last >= 0) && !big->cu[last].isNodePtr && (
|
||||
((vpn < L2V_VPN_SPECIAL) && ((big->cu[last].u.n.vpn+big->cu[last].span) == vpn))
|
||||
|| ((vpn >= L2V_VPN_SPECIAL) && (big->cu[last].u.n.vpn == vpn))))
|
||||
{
|
||||
big->cu[last].span += span;
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
big->cu[big->max].isNodePtr = 0;
|
||||
big->cu[big->max].u.n.vpn = vpn;
|
||||
big->cu[big->max].span = span;
|
||||
big->max++;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_TYPES_H__
|
||||
#define __L2V_TYPES_H__
|
||||
|
||||
|
||||
#include "WMROAM.h"
|
||||
#include "L2V_Defines.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
|
||||
// Pointer type: can point to NAND, or to a subtree
|
||||
// Bits: 0=isNodePtr, 1=hasSpanOF.
|
||||
// isNodePtr=0: vpn:L2V_BITS_VPN, span:L2V_BITS_NAND_SPAN
|
||||
// isNodePtr=1: nodeIdx:L2V_BITS_NODEIDX, span:L2V_BITS_NODE_SPAN
|
||||
// hasSpanOF: fetch 2 bytes from the right end of the node
|
||||
|
||||
typedef UInt32 lPtr_t;
|
||||
#define LPTR_IS_NODEPTR(_lptr) ((_lptr) & 1)
|
||||
#define LPTR_HASSPANOF(_lptr) (((_lptr) & 2) >> 1)
|
||||
#define LPTR_PACK_NAND(_cu) ( \
|
||||
(((_cu).hasSpanOF & 1) << 1) | \
|
||||
(((_cu).u.n.vpn & (((1 <<L2V_BITS_VPN)-1))) << 2) | \
|
||||
(((_cu).span & ((1<<L2V_BITS_NAND_SPAN)-1)) << (2+L2V_BITS_VPN)) \
|
||||
)
|
||||
#define LPTR_PACK_NODE(_cu) ( \
|
||||
1 | \
|
||||
(((_cu).hasSpanOF & 1) << 1) | \
|
||||
(((_cu).u.nodeIdx & ((1 << L2V_BITS_NODEIDX)-1)) << 2) | \
|
||||
(((_cu).span & (((1 <<L2V_BITS_NODE_SPAN)-1))) << (2+L2V_BITS_NODEIDX)) \
|
||||
)
|
||||
#define LPTR_UNPACK_NAND(_lptr, _cu) do { \
|
||||
(_cu).isNodePtr = 0; \
|
||||
(_cu).hasSpanOF = ((_lptr) >> 1) & 1; \
|
||||
(_cu).u.n.vpn = ((_lptr) >> 2) & ((1 << L2V_BITS_VPN)-1); \
|
||||
(_cu).span = ((_lptr) >> (2+L2V_BITS_VPN)) & ((1 << L2V_BITS_NAND_SPAN)-1); \
|
||||
} while (0)
|
||||
#define LPTR_UNPACK_NODE(_lptr, _cu) do { \
|
||||
(_cu).isNodePtr = 1; \
|
||||
(_cu).hasSpanOF = ((_lptr) >> 1) & 1; \
|
||||
(_cu).u.nodeIdx = ((_lptr) >> 2) & ((1 << L2V_BITS_NODEIDX)-1); \
|
||||
(_cu).span = ((_lptr) >> (2+L2V_BITS_NODEIDX)) & ((1 << L2V_BITS_NODE_SPAN)-1); \
|
||||
} while (0)
|
||||
#define LPTR_GET_NODEIDX(_lptr) (((_lptr) >> 2) & ((1 << L2V_BITS_NODEIDX)-1))
|
||||
#define LPTR_UNPACK(_lptr, _cu) do { \
|
||||
if LPTR_IS_NODEPTR(_lptr) { \
|
||||
LPTR_UNPACK_NODE(_lptr, _cu); \
|
||||
} else { \
|
||||
LPTR_UNPACK_NAND(_lptr, _cu); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
UInt32 isNodePtr; // Values: 0, 1 (true)... must not be any other value
|
||||
UInt32 hasSpanOF; // Values: 0, 1 (true)... ditto
|
||||
union {
|
||||
struct {
|
||||
UInt32 vpn;
|
||||
} n;
|
||||
UInt32 nodeIdx;
|
||||
} u;
|
||||
UInt32 span;
|
||||
} ContigUnpacked_t;
|
||||
|
||||
|
||||
// Node type: union for dynamic and fixed node types (and FreePool linkage)
|
||||
typedef union _lNode_t {
|
||||
union _lNode_t *nextFreePtr;
|
||||
|
||||
UInt8 bytes[L2V_NODE_SIZE];
|
||||
} lNode_t;
|
||||
CASSERT(L2V_NODE_SIZE == sizeof(lNode_t), lNode_t_size_matches);
|
||||
|
||||
#define L2V_LNODEBIG_MAX (L2V_MAX_CONTIG_PER_NODE+(L2V_SUCKUP_CHILDREN_MAX*2)+5)
|
||||
typedef struct {
|
||||
ContigUnpacked_t cu[L2V_LNODEBIG_MAX];
|
||||
UInt32 start;
|
||||
UInt32 max;
|
||||
} lNodeBig_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
lNode_t *Node; // Node pool allocated with malloc()
|
||||
lNode_t *FreePtr;
|
||||
UInt32 FreeCount;
|
||||
} FTLight_NodePool_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
// Logical space
|
||||
UInt32 numRoots;
|
||||
lPtr_t *Tree;
|
||||
UInt32 *TreeNodes;
|
||||
UInt32 *UpdatesSinceRepack;
|
||||
UInt32 RepackCounter;
|
||||
UInt32 treeVersion;
|
||||
|
||||
// Physical space
|
||||
UInt32 numSBs;
|
||||
UInt32 pagesPerSB;
|
||||
#if L2V_TRACK_VALID!=0
|
||||
UInt32 Valid[L2V_MAX_SB];
|
||||
#endif
|
||||
|
||||
// Memory
|
||||
FTLight_NodePool_t Pool;
|
||||
} L2V_t;
|
||||
|
||||
typedef struct {
|
||||
// Input:
|
||||
UInt32 lba;
|
||||
|
||||
// Output:
|
||||
UInt32 fromStart; // blocks from start of treeSpan
|
||||
UInt32 vpn;
|
||||
UInt32 span;
|
||||
|
||||
// Internal state:
|
||||
lNode_t *last_node;
|
||||
UInt32 next_lba;
|
||||
UInt32 next_nOfs;
|
||||
UInt32 nodeSize;
|
||||
UInt32 level;
|
||||
UInt32 treeVersion;
|
||||
} L2V_SearchCtx_t;
|
||||
|
||||
|
||||
// Helper functions
|
||||
|
||||
extern BOOL32 _L2V_NodeBig_PushContig(lNodeBig_t *big, ContigUnpacked_t *cu); // True: compressed with left
|
||||
extern BOOL32 _L2V_NodeBig_PushContig_Node(lNodeBig_t *big, UInt32 nodeIdx, UInt32 span); // True: compress with left (always false)
|
||||
extern BOOL32 _L2V_NodeBig_PushContig_Nand(lNodeBig_t *big, UInt32 vpn, UInt32 span); // True: compressed with left
|
||||
#define _L2V_NodeBig_WillCompress(_big, _vpn, _span) \
|
||||
((_big.max > 0) && (!_big.cu[_big.max-1].isNodePtr) && \
|
||||
(((_vpn < L2V_VPN_SPECIAL) && ((_big.cu[_big.max-1].u.n.vpn+_big.cu[_big.max-1].span) == _vpn)) \
|
||||
|| ((_vpn >= L2V_VPN_SPECIAL) && (_big.cu[_big.max-1].u.n.vpn == _vpn))))
|
||||
|
||||
|
||||
#endif // __L2V_TYPES_H__
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
|
||||
|
||||
#if L2V_TRACK_VALID!=0
|
||||
|
||||
void _L2V_ValidUp(UInt32 vpn, UInt32 count)
|
||||
{
|
||||
UInt32 sb = vpn / L2V.pagesPerSB;
|
||||
L2V.Valid[sb] += count;
|
||||
//l2v_assert_le(L2V.Valid[sb], sbsize);
|
||||
}
|
||||
|
||||
void _L2V_ValidDown(UInt32 vpn, UInt32 count)
|
||||
{
|
||||
UInt32 sb = vpn / L2V.pagesPerSB;
|
||||
//l2v_assert_ge(L2V.Valid[sb], count);
|
||||
L2V.Valid[sb] -= count;
|
||||
}
|
||||
|
||||
#endif // track valid
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_VALID_H__
|
||||
#define __L2V_VALID_H__
|
||||
|
||||
|
||||
#include "L2V_Defines.h"
|
||||
|
||||
#if L2V_TRACK_VALID!=0
|
||||
extern void _L2V_ValidUp(UInt32 vpn, UInt32 count);
|
||||
extern void _L2V_ValidDown(UInt32 vpn, UInt32 count);
|
||||
#else
|
||||
#define _L2V_ValidUp(vpn, count)
|
||||
#define _L2V_ValidDown(vpn, count)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __L2V_VALID_H__
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#define ENABLE_L2V_TREE (1)
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Author: Daniel J. Post (djp), dpost@apple.com
|
||||
|
||||
#include "WMROAM.h"
|
||||
|
||||
|
||||
void *WMR_MALLOC(UInt32 size)
|
||||
{
|
||||
void * ptr = malloc(size);
|
||||
if (ptr)
|
||||
{
|
||||
WMR_MEMSET(ptr, 0, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __WMROAM_H__
|
||||
#define __WMROAM_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UInt32 uint32_t
|
||||
#define Int32 int32_t
|
||||
#define UInt16 uint16_t
|
||||
#define Int16 int16_t
|
||||
#define UInt8 uint8_t
|
||||
#define Int8 int8_t
|
||||
#define BOOL32 bool
|
||||
#define TRUE32 true
|
||||
#define FALSE32 false
|
||||
|
||||
#define _WMR_ASSERT(e, file, line) { printf("%s:%u: failed assertion '%s'\nWaiting for debugger...\n", file, line, e); abort(); }
|
||||
#define WMR_ASSERT(e) if (!(e)) _WMR_ASSERT(#e, __FILE__, __LINE__)
|
||||
#define WMR_PANIC(format, args...) { printf(format , ##args); abort(); }
|
||||
#define WMR_MEMSET(a, b, c) memset(a, b, c)
|
||||
#define WMR_FREE(x, y) free(x)
|
||||
|
||||
extern void *WMR_MALLOC(UInt32 size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_TRACE_*
|
||||
//
|
||||
// Compile-time tracepoints (not supported)
|
||||
//
|
||||
#define WMR_TRACE_0(...)
|
||||
#define WMR_TRACE_1(...)
|
||||
#define WMR_TRACE_2(...)
|
||||
#define WMR_TRACE_3(...)
|
||||
#define WMR_TRACE_4(...)
|
||||
#define WMR_TRACE_IST_0(...)
|
||||
#define WMR_TRACE_IST_1(...)
|
||||
#define WMR_TRACE_IST_2(...)
|
||||
#define WMR_TRACE_IST_3(...)
|
||||
#define WMR_TRACE_IST_4(...)
|
||||
|
||||
#endif // __WMROAM_H__
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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.
|
||||
*/
|
||||
|
||||
#ifndef _YAFTLTYPES_H_
|
||||
#define _YAFTLTYPES_H_
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "yaFTL_Defines.h"
|
||||
#include "L2V/L2V_Extern.h"
|
||||
#include "WMRBuf.h"
|
||||
#include "yaFTL_meta.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Info generated by CalcGlobal
|
||||
UInt16 wPagesPerVb; /* the count of pages per virtual block */
|
||||
UInt16 wUserVbTotal; /* the total number of data virtual block */
|
||||
UInt32 dwUserPagesTotal; /* the total number of data sector */
|
||||
UInt16 wBytesPerPage; /* bytes per page (main) */
|
||||
UInt16 wNumOfBanks; /* the number of banks */
|
||||
UInt16 wBytesPerPageMeta; /* bytes per page (meta) */
|
||||
} FTLWMRDeviceInfo;
|
||||
|
||||
#define PAGES_PER_SUBLK (yaFTL_FTLDeviceInfo.wPagesPerVb)
|
||||
#define NUM_BANKS (yaFTL_FTLDeviceInfo.wNumOfBanks)
|
||||
#define FTL_AREA_SIZE (yaFTL_FTLDeviceInfo.wUserVbTotal)
|
||||
#define USER_PAGES_TOTAL (yaFTL_FTLDeviceInfo.dwUserPagesTotal)
|
||||
#define BYTES_PER_PAGE (yaFTL_FTLDeviceInfo.wBytesPerPage)
|
||||
#define BYTES_PER_PAGE_META (yaFTL_FTLDeviceInfo.wBytesPerPageMeta)
|
||||
#define NUM_BANKS (yaFTL_FTLDeviceInfo.wNumOfBanks)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// UInt32 serialCounter; // serial allocation counter that would be used for restore
|
||||
// UInt16 validPagesNo; // Number of valid pages in block
|
||||
UInt32 erasableCount;
|
||||
UInt16 validPagesDNo;
|
||||
UInt16 validPagesINo;
|
||||
UInt16 pagesRead;
|
||||
UInt8 status;
|
||||
UInt8 eraseBeforeUse;
|
||||
UInt8 pagesReadSubCounter;
|
||||
} BlockEntry;
|
||||
|
||||
// TOCEntry: pointer to cache index if the given index page is in the cache, or pointer to NAND if not.
|
||||
// P.S.: not related to BlockTOCs.
|
||||
typedef struct
|
||||
{
|
||||
UInt32 indexPage; // location on the flash
|
||||
UInt16 cacheIndex; // 0xff means not cached
|
||||
} TOCEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 *indexPage; // pointer to the page address array
|
||||
UInt32 tocEntry; // index of the TOCEntry
|
||||
UInt16 counter; // number of hits on this cache
|
||||
UInt16 status; // free/occupied/dirty
|
||||
} CacheIndexEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 ddwPagesWrittenCnt;
|
||||
UInt64 ddwPagesReadCnt;
|
||||
UInt64 ddwFTLWriteCnt;
|
||||
UInt64 ddwFTLReadCnt;
|
||||
UInt64 ddwDataGCCnt;
|
||||
UInt64 ddwIndexGCCnt;
|
||||
UInt64 ddwEmptyGCDataCnt; /* case there is data to copy */
|
||||
UInt64 ddwEmptyGCIndexCnt; /* case there is data to copy */
|
||||
UInt64 ddwValidDataPages;
|
||||
UInt64 ddwValidIndexPages;
|
||||
UInt64 ddwFreeBlks;
|
||||
UInt64 ddwFTLRestoreCnt;
|
||||
UInt64 ddwReadDisturbHandleCall;
|
||||
UInt64 ddwWearLevelCnt;
|
||||
UInt64 ddwFlushCnt;
|
||||
UInt64 ddwRefreshCnt;
|
||||
UInt64 ddwRead[8];
|
||||
UInt64 ddwReadOver8;
|
||||
UInt64 ddwWrite[8];
|
||||
UInt64 ddwWriteOver8;
|
||||
UInt64 ddwNodesFree;
|
||||
UInt64 ddwNodesTotal;
|
||||
} FTLStatistics;
|
||||
|
||||
#define FTL_STATISTICS_DESCREPTION { \
|
||||
"ddwPagesWrittenCnt", \
|
||||
"ddwPagesReadCnt", \
|
||||
"ddwFTLWriteCnt", \
|
||||
"ddwFTLReadCnt", \
|
||||
"ddwDataGCCnt", \
|
||||
"ddwIndexGCCnt", \
|
||||
"ddwEmptyGCDataCnt", \
|
||||
"ddwEmptyGCIndexCnt", \
|
||||
"ddwValidDataPages", \
|
||||
"ddwValidIndexPages", \
|
||||
"ddwFreeBlks", \
|
||||
"ddwFTLRestoreCnt", \
|
||||
"ddwReadDisturbHandleCall", \
|
||||
"ddwWearLevelCnt", \
|
||||
"ddwFlushCnt", \
|
||||
"ddwRefreshCnt", \
|
||||
"ddwRead1", \
|
||||
"ddwRead2", \
|
||||
"ddwRead3", \
|
||||
"ddwRead4", \
|
||||
"ddwRead5", \
|
||||
"ddwRead6", \
|
||||
"ddwRead7", \
|
||||
"ddwRead8", \
|
||||
"ddwReadOver8", \
|
||||
"ddwWrite1", \
|
||||
"ddwWrite2", \
|
||||
"ddwWrite3", \
|
||||
"ddwWrite4", \
|
||||
"ddwWrite5", \
|
||||
"ddwWrite6", \
|
||||
"ddwWrite7", \
|
||||
"ddwWrite8", \
|
||||
"ddwWriteOver8", \
|
||||
"ddwNodesFree", \
|
||||
"ddwNodesTotal", \
|
||||
}
|
||||
|
||||
#define GCFIFO_DEPTH 16
|
||||
typedef struct
|
||||
{
|
||||
UInt32 block[GCFIFO_DEPTH + 1];
|
||||
UInt32 head, tail; // head==tail means it is empty
|
||||
} GC_Fifo_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GCD_IDLE,
|
||||
GCD_EVICT,
|
||||
GCD_ERASE,
|
||||
GCD_FIXINDEX_RETRY,
|
||||
GCD_FIXDATA_RETRY,
|
||||
} GCDState;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// In:
|
||||
UInt32 in_block;
|
||||
|
||||
// Work FIFO for error handling
|
||||
GC_Fifo_t workFifo;
|
||||
|
||||
// Choose out:
|
||||
UInt32 chosenBlock;
|
||||
UInt32 chosenValid;
|
||||
UInt32 chosenErases;
|
||||
|
||||
// Buffers:
|
||||
UInt32 outstandingAllocs;
|
||||
Buffer *tmpB1, *tmpB2, *tmpB3;
|
||||
UInt32 *TOCbuff;
|
||||
UInt8 *pageBuffer;
|
||||
|
||||
// GC zone:
|
||||
UInt32 *vpns;
|
||||
UInt8 *zone;
|
||||
PageMeta_t *meta;
|
||||
UInt32 curZoneSize;
|
||||
UInt32 ueccCounter;
|
||||
|
||||
// State:
|
||||
GCDState state;
|
||||
UInt32 curPage;
|
||||
UInt32 pagesRange;
|
||||
UInt32 pagesCopied;
|
||||
Int32 gcDataAdjust; // only meaningful for data GC
|
||||
|
||||
L2V_SearchCtx_t read_c; // Search context for GC translation
|
||||
} GC_Ctx_t;
|
||||
|
||||
#define ERASE_NOW_LIST_SIZE 5
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WMR_BufZone_t BufZone; // Buffer zone allocators
|
||||
WMR_BufZone_t BufZone_IndexCache; // ...
|
||||
UInt16 controlPageNo, indexPageRatio; /* TOC of each block contains Lpa for each page written to block */
|
||||
UInt32 indexSize; /* index size in blocks */
|
||||
UInt32 dataSize;
|
||||
UInt32 logicalPartitionSize; /* partititon size in pages exposed to file system */
|
||||
UInt16 TOCtableEntriesNo; /* number of entries in index TOC table */
|
||||
|
||||
UInt16 freeCachePages;
|
||||
UInt16 erasedBlockCount;
|
||||
#ifndef AND_READONLY
|
||||
UInt16 nextFreeCachePage;
|
||||
UInt64 cxtAllocation;
|
||||
UInt32 currentCXTIndex, FTLRestoreCnt;
|
||||
UInt8 cxtEraseCounter;
|
||||
UInt32 currentDBlockAllocationNo;
|
||||
UInt8 cxtValid;
|
||||
UInt8 formatWasCalled;
|
||||
BOOL32 readLimit;
|
||||
UInt16 eraseNowList[ERASE_NOW_LIST_SIZE];
|
||||
#endif
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UInt32 block;
|
||||
UInt32 *TOC;
|
||||
UInt16 nextPage;
|
||||
WeaveSeq_t minWeaveSeq;
|
||||
} data;
|
||||
struct
|
||||
{
|
||||
UInt32 block;
|
||||
UInt32 *TOC;
|
||||
UInt16 nextPage;
|
||||
WeaveSeq_t minWeaveSeq;
|
||||
} index;
|
||||
|
||||
WeaveSeq_t weaveSeq;
|
||||
UInt32 lastBlock;
|
||||
} wrState;
|
||||
|
||||
struct
|
||||
{
|
||||
UInt32 size;
|
||||
UInt32 curAge;
|
||||
UInt32 free;
|
||||
UInt32 isData;
|
||||
UInt32 **BTOC;
|
||||
UInt32 *sb;
|
||||
Int32 *age;
|
||||
WMR_BufZone_t BufZone; // Buffer zone allocator
|
||||
|
||||
// For srcVpn:
|
||||
UInt32 srcSize;
|
||||
UInt32 curSrc;
|
||||
UInt32 *srcSb;
|
||||
UInt32 **srcVpn;
|
||||
UInt32 isLocked;
|
||||
} BTOCcache;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UInt32 allocdBlocks;
|
||||
Int32 freeBlocks;
|
||||
UInt32 validPages;
|
||||
} data;
|
||||
struct
|
||||
{
|
||||
UInt32 allocdBlocks;
|
||||
Int32 freeBlocks;
|
||||
UInt32 validPages;
|
||||
} index;
|
||||
UInt32 freeBlocks;
|
||||
BOOL32 distCheckable;
|
||||
} seaState;
|
||||
|
||||
struct
|
||||
{
|
||||
UInt32 blocksSince;
|
||||
BOOL32 pointOfNoReturn;
|
||||
} wearLevel;
|
||||
|
||||
struct
|
||||
{
|
||||
UInt32 pagesWritten;
|
||||
UInt32 erases;
|
||||
} periodicCxt;
|
||||
|
||||
TOCEntry *tocArray; /* [TOC_SIZE] Table of content that contains location of index pages in flash and index cache */
|
||||
CacheIndexEntry *indexCache; /* [INDEX_CACHE_SIZE] cached index pages */
|
||||
BlockEntry *blockArray; /* [YAFTL_NO_OF_BLOCKS] block information */
|
||||
UInt32 *restoreTOC; // blockTOC for restore
|
||||
|
||||
PageMeta_t *meta_restoreIdx;
|
||||
PageMeta_t *meta_restoreData;
|
||||
PageMeta_t *meta_readCxt;
|
||||
PageMeta_t *meta_quickRestore;
|
||||
PageMeta_t *meta_invalidateCxt;
|
||||
PageMeta_t *meta_writeCxt;
|
||||
PageMeta_t *meta_restoreMountErase;
|
||||
PageMeta_t *meta_restoreMount;
|
||||
PageMeta_t *meta_clearEntryInCache;
|
||||
PageMeta_t *meta_writeBTOC;
|
||||
PageMeta_t *meta_indexLoadDirty;
|
||||
PageMeta_t *meta_getStats;
|
||||
PageMeta_t *meta_GetBlockTOC;
|
||||
PageMeta_t *meta_IsDataPageCurrent;
|
||||
PageMeta_t *meta_WriteZoneData;
|
||||
|
||||
UInt8 *quickRestore_tBuff;
|
||||
UInt32 *tmpReadBuffer; // = NULL;
|
||||
UInt32 readBufferIndex; // = 0xffffffff;
|
||||
PageMeta_t *writeMdPtr; // = NULL;
|
||||
UInt32 *multiReadvpN; // = NULL;
|
||||
PageMeta_t *readMdPtr; // = NULL;
|
||||
PageMeta_t *singleMdPtr;
|
||||
UInt32 cxtSize, cxtSizeTOC, cxtSizeBlockStatus, cxtSizeBlockRead,
|
||||
cxtSizeBlockErase, cxtSizeValidPagesD, cxtSizeValidPagesI;
|
||||
UInt32 currentCxtVpn; // = 0xffffffff;
|
||||
UInt16 cxtTable[FTL_CXT_SECTION_SIZE];
|
||||
UInt32 maxEraseCount, minEraseCount; // = 0
|
||||
|
||||
UInt32 indexCacheSize; // = DEFAULT_INDEX_CACHE_SIZE;
|
||||
UInt8 exportedRatio; // = DEFAULT_EXPO_RATIO;
|
||||
|
||||
// Garbage collection structures
|
||||
struct
|
||||
{
|
||||
UInt32 zoneSize;
|
||||
GC_Ctx_t data;
|
||||
GC_Ctx_t index;
|
||||
WMR_BufZone_t BufZone; // Buffer zone allocator
|
||||
PageMeta_t *meta_buf;
|
||||
} gc;
|
||||
|
||||
// Read search context
|
||||
L2V_SearchCtx_t read_c;
|
||||
} yaFTL_t;
|
||||
|
||||
#endif /* _YAFTLTYPES_H_ */
|
||||
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "yaFTL_whoami.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "yaFTL_BTOC.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "VFL.h"
|
||||
#include "FTL.h"
|
||||
#include "yaFTLTypes.h"
|
||||
#include "yaFTL_Defines.h"
|
||||
|
||||
// Extern context struct
|
||||
extern yaFTL_t yaFTL;
|
||||
extern FTLWMRDeviceInfo yaFTL_FTLDeviceInfo;
|
||||
extern Int32 _readPage(UInt32 vpn, UInt8 *pageData, PageMeta_t *mdPtr, BOOL32 bInternalOp, BOOL32 boolCleanCheck, BOOL32 scrubOnUECC);
|
||||
extern ANDStatus invalidateCXT(void);
|
||||
|
||||
BOOL32 BTOC_Init()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
yaFTL.BTOCcache.size = YAFTL_BTOCCACHE_SIZE_PER * 2;
|
||||
WMR_ASSERT(yaFTL.BTOCcache.size <= 32);
|
||||
yaFTL.BTOCcache.srcSize = YAFTL_BTOCCACHE_SRCSIZE;
|
||||
yaFTL.BTOCcache.curSrc = yaFTL.BTOCcache.srcSize-1;
|
||||
|
||||
yaFTL.BTOCcache.curAge = 0;
|
||||
yaFTL.BTOCcache.age = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.age) * yaFTL.BTOCcache.size);
|
||||
yaFTL.BTOCcache.sb = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.sb) * yaFTL.BTOCcache.size);
|
||||
yaFTL.BTOCcache.BTOC = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.BTOC) * yaFTL.BTOCcache.size);
|
||||
yaFTL.BTOCcache.srcVpn = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.srcVpn) * yaFTL.BTOCcache.srcSize);
|
||||
yaFTL.BTOCcache.srcSb = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.srcSb) * yaFTL.BTOCcache.srcSize);
|
||||
yaFTL.BTOCcache.isLocked = 0;
|
||||
|
||||
// Check for allocation failure
|
||||
if ((NULL == yaFTL.BTOCcache.age) || (NULL == yaFTL.BTOCcache.sb) || (NULL == yaFTL.BTOCcache.BTOC)
|
||||
|| (NULL == yaFTL.BTOCcache.srcVpn) || (NULL == yaFTL.BTOCcache.srcSb))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
yaFTL.BTOCcache.sb[i] = 0xffffffff;
|
||||
}
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
yaFTL.BTOCcache.srcSb[i] = 0xffffffff;
|
||||
yaFTL.BTOCcache.srcVpn[i] = WMR_MALLOC(sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
WMR_MEMSET(yaFTL.BTOCcache.srcVpn[i], 0xff, sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
}
|
||||
|
||||
yaFTL.BTOCcache.free = (1 << yaFTL.BTOCcache.size) - 1;
|
||||
yaFTL.BTOCcache.isData = (1 << YAFTL_BTOCCACHE_SIZE_PER) - 1;
|
||||
|
||||
// Allocate buffers
|
||||
WMR_BufZone_Init(&yaFTL.BTOCcache.BufZone);
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
yaFTL.BTOCcache.BTOC[i] = (UInt32*)WMR_Buf_Alloc_ForDMA(&yaFTL.BTOCcache.BufZone, yaFTL.controlPageNo * BYTES_PER_PAGE);
|
||||
}
|
||||
|
||||
if (!WMR_BufZone_FinishedAllocs(&yaFTL.BTOCcache.BufZone)) {
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
WMR_BufZone_Rebase(&yaFTL.BTOCcache.BufZone, (void**)&yaFTL.BTOCcache.BTOC[i]);
|
||||
}
|
||||
|
||||
WMR_BufZone_FinishedRebases(&yaFTL.BTOCcache.BufZone);
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
void BTOC_Close()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
WMR_BufZone_Free(&yaFTL.BTOCcache.BufZone);
|
||||
|
||||
if (NULL != yaFTL.BTOCcache.age)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.age, sizeof(*yaFTL.BTOCcache.age) * yaFTL.BTOCcache.size);
|
||||
}
|
||||
if (NULL != yaFTL.BTOCcache.sb)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.sb, sizeof(*yaFTL.BTOCcache.sb) * yaFTL.BTOCcache.size);
|
||||
}
|
||||
if (NULL != yaFTL.BTOCcache.BTOC)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.BTOC, sizeof(*yaFTL.BTOCcache.BTOC) * yaFTL.BTOCcache.size);
|
||||
}
|
||||
// Free srcVpn memory
|
||||
if (NULL != yaFTL.BTOCcache.srcSb)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.srcSb, sizeof(*yaFTL.BTOCcache.srcSb) * yaFTL.BTOCcache.srcSize);
|
||||
}
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.srcVpn[i], sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
}
|
||||
if (NULL != yaFTL.BTOCcache.srcVpn)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.srcVpn, sizeof(*yaFTL.BTOCcache.srcVpn) * yaFTL.BTOCcache.srcSize);
|
||||
}
|
||||
|
||||
yaFTL.BTOCcache.age = NULL;
|
||||
yaFTL.BTOCcache.sb = NULL;
|
||||
yaFTL.BTOCcache.BTOC = NULL;
|
||||
yaFTL.BTOCcache.srcSb = NULL;
|
||||
yaFTL.BTOCcache.srcVpn = NULL;
|
||||
|
||||
yaFTL.BTOCcache.size = 0;
|
||||
|
||||
yaFTL.BTOCcache.srcSize = 0;
|
||||
}
|
||||
|
||||
void BTOC_BootFixup()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if (0xfffffffd == yaFTL.BTOCcache.sb[i])
|
||||
{
|
||||
yaFTL.BTOCcache.sb[i] = yaFTL.wrState.data.block;
|
||||
}
|
||||
if (0xfffffffe == yaFTL.BTOCcache.sb[i])
|
||||
{
|
||||
yaFTL.BTOCcache.sb[i] = yaFTL.wrState.index.block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 *BTOC_Alloc(UInt32 sb, BOOL32 isData)
|
||||
{
|
||||
UInt32 i, minIdx, isData32 = (isData ? 1 : 0);
|
||||
Int32 minAge;
|
||||
|
||||
// Get a srcVpn
|
||||
yaFTL.BTOCcache.curSrc = (yaFTL.BTOCcache.curSrc + 1) % yaFTL.BTOCcache.srcSize;
|
||||
yaFTL.BTOCcache.srcSb[yaFTL.BTOCcache.curSrc] = sb;
|
||||
WMR_MEMSET(yaFTL.BTOCcache.srcVpn[yaFTL.BTOCcache.curSrc], 0xff, sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
|
||||
// Get a BTOC
|
||||
yaFTL.BTOCcache.curAge++;
|
||||
|
||||
minAge = 0x7fffffff;
|
||||
minIdx = 0xffffffff;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if (((yaFTL.BTOCcache.isData & (1 << i)) == (isData32 << i))
|
||||
&& (yaFTL.BTOCcache.free & (1 << i))
|
||||
&& (yaFTL.BTOCcache.age[i] < minAge)
|
||||
&& ((yaFTL.BTOCcache.isLocked & (1 << i)) == 0))
|
||||
{
|
||||
minAge = yaFTL.BTOCcache.age[i];
|
||||
minIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (0xffffffff != minIdx) {
|
||||
yaFTL.BTOCcache.free &= ~(1 << minIdx);
|
||||
yaFTL.BTOCcache.sb[minIdx] = sb;
|
||||
yaFTL.BTOCcache.age[minIdx] = yaFTL.BTOCcache.curAge;
|
||||
return yaFTL.BTOCcache.BTOC[minIdx];
|
||||
}
|
||||
#ifndef AND_READONLY
|
||||
// Invalidate context
|
||||
if (yaFTL.cxtValid == 1)
|
||||
{
|
||||
invalidateCXT();
|
||||
yaFTL.cxtValid = 0;
|
||||
}
|
||||
WMR_PANIC("Couldn't allocate a BTOC");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UInt32 BTOC_GetSrc(UInt32 destVpn)
|
||||
{
|
||||
UInt32 i, sb, idx;
|
||||
|
||||
sb = destVpn / PAGES_PER_SUBLK;
|
||||
idx = destVpn % PAGES_PER_SUBLK;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
if (sb == yaFTL.BTOCcache.srcSb[i]) {
|
||||
return yaFTL.BTOCcache.srcVpn[i][idx];
|
||||
}
|
||||
}
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
void BTOC_SetSrc(UInt32 destVpn, UInt32 srcVpn)
|
||||
{
|
||||
UInt32 i, sb, idx;
|
||||
|
||||
sb = destVpn / PAGES_PER_SUBLK;
|
||||
idx = destVpn % PAGES_PER_SUBLK;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
if (sb == yaFTL.BTOCcache.srcSb[i]) {
|
||||
yaFTL.BTOCcache.srcVpn[i][idx] = srcVpn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BTOC_Dealloc(UInt32 *BTOC)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if (BTOC == yaFTL.BTOCcache.BTOC[i])
|
||||
{
|
||||
yaFTL.BTOCcache.free |= (1 << i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifndef AND_READONLY
|
||||
// Invalidate context
|
||||
if (yaFTL.cxtValid == 1)
|
||||
{
|
||||
invalidateCXT();
|
||||
yaFTL.cxtValid = 0;
|
||||
}
|
||||
WMR_PANIC("Couldn't deallocate BTOC: 0x%x", BTOC);
|
||||
#endif
|
||||
}
|
||||
|
||||
UInt32 *BTOC_Search(UInt32 sb, BOOL32 isData)
|
||||
{
|
||||
UInt32 i, isData32 = (isData ? 1 : 0);
|
||||
Int32 maxAge = -1;
|
||||
UInt32 *best = NULL;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if ((yaFTL.BTOCcache.sb[i] == sb) && (yaFTL.BTOCcache.age[i] > maxAge) && ((yaFTL.BTOCcache.isData & (1 << i)) == (isData32 << i)))
|
||||
{
|
||||
maxAge = yaFTL.BTOCcache.age[i];
|
||||
best = yaFTL.BTOCcache.BTOC[i];
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
void BTOC_Lock(UInt32 sb)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if ((yaFTL.BTOCcache.sb[i] == sb) && ((yaFTL.BTOCcache.free & (1 << i)) == 0))
|
||||
{
|
||||
yaFTL.BTOCcache.isLocked |= (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BTOC_Unlock(UInt32 sb)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if ((yaFTL.BTOCcache.sb[i] == sb) && (yaFTL.BTOCcache.isLocked & (1 << i)))
|
||||
{
|
||||
yaFTL.BTOCcache.isLocked &= ~(1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ANDStatus BTOC_Read(UInt32 vpn, UInt32 *bTOC, PageMeta_t *mdPtr, BOOL32 val, BOOL32 scrubOnUECC, UInt32 upperBound)
|
||||
{
|
||||
UInt16 i;
|
||||
ANDStatus status = FTL_CRITICAL_ERROR;
|
||||
|
||||
for (i = 0; i < yaFTL.controlPageNo; i++)
|
||||
{
|
||||
status = _readPage(vpn + i, ((UInt8 *)bTOC) + (i * BYTES_PER_PAGE), mdPtr, val, TRUE32, scrubOnUECC);
|
||||
if (status != FTL_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status == FTL_SUCCESS)
|
||||
{
|
||||
UInt32 * tmpPtr = (UInt32 *)bTOC;
|
||||
for(i = 0; i < ((yaFTL.controlPageNo * BYTES_PER_PAGE) >> 2);i++)
|
||||
if(tmpPtr[i] >= upperBound)
|
||||
{
|
||||
tmpPtr[i] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void BTOC_SetAll(UInt32 *bTOC, UInt8 value)
|
||||
{
|
||||
WMR_MEMSET(bTOC, value, yaFTL.controlPageNo * BYTES_PER_PAGE);
|
||||
}
|
||||
|
||||
|
||||
void BTOC_Copy(UInt32 *left, UInt32 *right, UInt32 upperBound)
|
||||
{
|
||||
UInt16 i;
|
||||
for(i = 0; i < ((yaFTL.controlPageNo * BYTES_PER_PAGE) >> 2);i++)
|
||||
if(right[i] >= upperBound)
|
||||
{
|
||||
left[i] = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
left[i] = right[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 BTOC_Get(UInt32 *bTOC, UInt32 offset, UInt32 upperBound)
|
||||
{
|
||||
if(bTOC[offset] >= upperBound)
|
||||
{
|
||||
return 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bTOC[offset];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 BTOC_Set(UInt32 *bTOC, UInt32 offset, UInt32 val, UInt32 upperBound)
|
||||
{
|
||||
if(val >= upperBound)
|
||||
{
|
||||
bTOC[offset] = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
bTOC[offset] = val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __YAFTL_BTOC_H__
|
||||
#define __YAFTL_BTOC_H__
|
||||
|
||||
// Includes
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "yaFTLTypes.h"
|
||||
#include "yaFTL_meta.h"
|
||||
|
||||
// Defines and types declared elsewhere
|
||||
|
||||
// Prototypes:
|
||||
|
||||
// BTOC init/alloc/dealloc
|
||||
extern BOOL32 BTOC_Init(void);
|
||||
extern void BTOC_BootFixup(void);
|
||||
extern void BTOC_Close(void);
|
||||
extern UInt32 *BTOC_Alloc(UInt32 sb, BOOL32 isData);
|
||||
extern void BTOC_Dealloc(UInt32 *BTOC);
|
||||
extern UInt32 *BTOC_Search(UInt32 sb, BOOL32 isData);
|
||||
extern void BTOC_Lock(UInt32 sb);
|
||||
extern void BTOC_Unlock(UInt32 sb);
|
||||
|
||||
// Read
|
||||
extern ANDStatus BTOC_Read(UInt32 vpn, UInt32 *bTOC, PageMeta_t *mdPtr, BOOL32 val, BOOL32 scrubOnUECC, UInt32 upperBound);
|
||||
|
||||
// Src for GC
|
||||
extern void BTOC_SetSrc(UInt32 destVpn, UInt32 srcVpn);
|
||||
extern UInt32 BTOC_GetSrc(UInt32 destVpn);
|
||||
|
||||
// Getters/setters
|
||||
extern void BTOC_SetAll(UInt32 *bTOC, UInt8 value);
|
||||
extern UInt32 BTOC_Get(UInt32 *bTOC, UInt32 offset, UInt32 upperBound);
|
||||
extern UInt32 BTOC_Set(UInt32 *bTOC, UInt32 offset, UInt32 val, UInt32 upperBound);
|
||||
|
||||
// Copy
|
||||
extern void BTOC_Copy(UInt32 *left, UInt32 *right, UInt32 upperBound);
|
||||
|
||||
#endif // ----- #ifndef __YAFTL_BTOC_H__
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __YAFTL_DEFINES_H__
|
||||
#define __YAFTL_DEFINES_H__
|
||||
|
||||
|
||||
#define YAFTLDBG_INIT (1 << 0)
|
||||
#define YAFTLDBG_FORMAT (1 << 1)
|
||||
#define YAFTLDBG_READ (1 << 2)
|
||||
#define YAFTLDBG_WRITE (1 << 3)
|
||||
#define YAFTLDBG_ERASE (1 << 4)
|
||||
#define YAFTLDBG_MISC (1 << 5)
|
||||
#define YAFTLDBG_ERROR (1 << 6)
|
||||
#define YAFTLDBG_OPEN (1 << 7)
|
||||
#define YAFTLDBG_INFO (1 << 8)
|
||||
|
||||
//#define YAFTL_DEBUG (YAFTLDBG_INIT | YAFTLDBG_ERROR | YAFTLDBG_INFO)
|
||||
#define YAFTL_DEBUG (YAFTLDBG_ERROR)
|
||||
#ifdef YAFTL_DEBUG
|
||||
#define YAFTL_ENABLE_DEBUG_PRINT (0xff)
|
||||
|
||||
# define debug(fac, fmt, args ...) \
|
||||
do { \
|
||||
if (YAFTLDBG_ ## fac & YAFTL_DEBUG & YAFTL_ENABLE_DEBUG_PRINT) { \
|
||||
_WMR_PRINT("yaFTL::%s(l:%d): " fmt "\n", __FUNCTION__, __LINE__, ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define debug(fac, fmt, args ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define FREE_BLK_TRH (5) /* number of units we require to be avaiable at any time */
|
||||
#define INDEX_AREA (1) /* block belongs to Index area */
|
||||
#define DATA_AREA (2) /* block belongs to data area */
|
||||
#define FREE_I_BLOCK_TRS (2) /* minimum free blocks within index area */
|
||||
#define DEFAULT_INDEX_CACHE_SIZE (10) /* index cached pages */
|
||||
#define INDEX_BLOCKS_RATIO (3) /* ratio of index area in flash to required index area by flash size */
|
||||
#define DEFAULT_EXPO_RATIO (99) /* percentage of data area exposed to file system */
|
||||
#define CXT_ERASE_LIMIT (30)
|
||||
|
||||
|
||||
#define IC_DIRTY_PAGE 1
|
||||
#define IC_BUSY_PAGE 2
|
||||
#define FREE_CACHE_PAGE 0xffff
|
||||
|
||||
#define BLOCK_FREE (0xFF) /* block marked as free */
|
||||
#define BLOCK_ALLOCATED (1) /* block marked as allocated for data area */
|
||||
#define BLOCK_CURRENT (4) /* block marked as current in data area */
|
||||
|
||||
#define BLOCK_GC (8) /* block in data area goes through GC process */
|
||||
|
||||
#define BLOCK_I_FREE (0xFF) /* block marked as free */
|
||||
#define BLOCK_I_CURRENT (32) /* block marked as current index block */
|
||||
#define BLOCK_I_ALLOCATED (64) /* block marked as idex block */
|
||||
#define BLOCK_I_GC (128) /* block in index area goes through GC process */
|
||||
#define BLOCK_TO_BE_ERASED (0x1) /* erase block before use . make sure the block is not erased before current block is closed */
|
||||
#define BLOCK_TO_BE_ERASED_ALIGNED_DATA (0x2) /* erase block before use . make sure the block is not erased before current block is closed */
|
||||
#define BLOCK_TO_BE_ERASED_ALIGNED_INDEX (0x4) /* erase block before use . make sure the block is not erased before current block is closed */
|
||||
#define BLOCK_READ_SCATTER (0x8) /* mark a block as being used in multi-read operation */
|
||||
#define BLOCK_TO_BE_MOVED (0x80) /* use it as an idication that block is to be refreshed after full mount is complete due to UECCs */
|
||||
|
||||
#define ERASE_IDLE_LIMIT (5) /* number of free blocks to be erased in idle time */
|
||||
|
||||
#define BLOCK_CTX_CNTR (2) /* block marked as CXT */
|
||||
#define BLOCK_CTX_CURRENT (16) /* block marked as current CXT */
|
||||
#define INDEX_PAGE_MARK (0x80000000) /* to be defined */
|
||||
|
||||
#define YAFTL_READ_DISTURB_LIMIT YAFTL_RC_THRESHOLD /* read disturb limit */
|
||||
|
||||
#define MIN_RESTORE_BUFFER (0x10000)
|
||||
#define MAX_RESTORE_BUFFER (0x200000)
|
||||
#define YAFTL_WEARLEVEL_PERIOD 30
|
||||
#define ERASE_COUNT_GAP_LIMIT 100
|
||||
#define ERASE_COUNT_GAP_UPPER_LIMIT 500
|
||||
#define STATIC_WEARLEVEL_TRIGGER 1000
|
||||
#define NAND_MOUNT_INDEX_SIZE 1000
|
||||
#define YAFTL_WRITE_MAX_STRIPES 32
|
||||
#define YAFTL_INDEX_CACHE_COUNTER_LIMIT 0xFFFF
|
||||
#define PAGES_READ_SUB_COUNTER_LIMIT YAFTL_RC_MULTIPLIER
|
||||
|
||||
// GCZONE_DOUBLEUPTO defines the point up to which we will multiply banks to.
|
||||
// It is similar to setting a minimum of 16, but works with non-pow-2 configs.
|
||||
#define GCZONE_DOUBLEUPTO 16
|
||||
#define YAFTL_GC_RATIO_SCALAR 4
|
||||
|
||||
// Maximum number of TOC pages/block to support
|
||||
#define MAX_TOC_PAGES 4
|
||||
#define YAFTL_BTOCCACHE_SIZE_PER 2
|
||||
#define YAFTL_BTOCCACHE_SRCSIZE 2
|
||||
|
||||
// make the function pointers in vfl struct look like the old vfl functions
|
||||
#ifndef AND_READONLY
|
||||
#define VFL_Format (yaFTL_VFLFunctions.Format)
|
||||
#define VFL_Write (yaFTL_VFLFunctions.WriteSinglePage)
|
||||
#define VFL_Erase (yaFTL_VFLFunctions.Erase)
|
||||
#define VFL_ChangeFTLCxtVbn (yaFTL_VFLFunctions.ChangeFTLCxtVbn)
|
||||
#define VFL_WriteMultiplePagesInVb (yaFTL_VFLFunctions.WriteMultiplePagesInVb)
|
||||
#endif // ! AND_READONLY
|
||||
#define VFL_Init (yaFTL_VFLFunctions.Init)
|
||||
#define VFL_Open (yaFTL_VFLFunctions.Open)
|
||||
#define VFL_Close (yaFTL_VFLFunctions.Close)
|
||||
#define VFL_ReadMultiplePagesInVb (yaFTL_VFLFunctions.ReadMultiplePagesInVb)
|
||||
#define VFL_ReadScatteredPagesInVb (yaFTL_VFLFunctions.ReadScatteredPagesInVb)
|
||||
#define VFL_Read (yaFTL_VFLFunctions.ReadSinglePage)
|
||||
#define VFL_GetFTLCxtVbn (yaFTL_VFLFunctions.GetFTLCxtVbn)
|
||||
//#define VFL_GetAddress (yaFTL_VFLFunctions.GetAddress)
|
||||
#define VFL_GetDeviceInfo (yaFTL_VFLFunctions.GetDeviceInfo)
|
||||
#define VFL_GetStruct (yaFTL_VFLFunctions.GetStruct)
|
||||
#define VFL_SetStruct (yaFTL_VFLFunctions.SetStruct)
|
||||
|
||||
#endif // ----- #ifndef _YAFTL_DEFINES_H__INC -----
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __YAFTL_GC_H__
|
||||
#define __YAFTL_GC_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "ANDTypes.h"
|
||||
|
||||
// General setup/close
|
||||
extern ANDStatus YAFTL_GC_Init(void);
|
||||
extern void YAFTL_GC_Close(void);
|
||||
|
||||
// Called by Write
|
||||
extern void YAFTL_GC_PreWrite(UInt32 writeSize);
|
||||
|
||||
// For error recovery
|
||||
extern void YAFTL_GC_Data_Enq(UInt32 block);
|
||||
extern UInt32 YAFTL_GC_Data_Deq_sb(UInt32 block);
|
||||
extern void YAFTL_GC_Index_Enq(UInt32 block);
|
||||
|
||||
// Direct access to the machines
|
||||
extern ANDStatus YAFTL_GC_Index(UInt32 block, BOOL32 scrubOnUECC);
|
||||
extern ANDStatus YAFTL_GC_Data(UInt32 block, BOOL32 scrubOnUECC);
|
||||
|
||||
#ifdef AND_READONLY
|
||||
#define CheckBlockDist(x)
|
||||
#else
|
||||
extern void CheckBlockDist(void);
|
||||
#endif
|
||||
|
||||
#endif // ----- #ifndef __YAFTL_GC_H__
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __YAFTL_META_H__
|
||||
#define __YAFTL_META_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
#if NAND_PPN
|
||||
#include "yaFTL_meta_ppn.h"
|
||||
#else
|
||||
// Default to raw to avoid compilation errors--meta isn't needed by some of the parsers that include yaFTLTypes.h
|
||||
#include "yaFTL_meta_raw.h"
|
||||
#endif
|
||||
|
||||
#endif // __YAFTL_META_H__
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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 "yaFTL_whoami.h"
|
||||
#include "yaFTL_meta_ppn.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "yaFTLTypes.h"
|
||||
|
||||
extern yaFTL_t yaFTL;
|
||||
|
||||
|
||||
void SetupMeta_Data(PageMeta_t *__meta, UInt32 lba, UInt32 count)
|
||||
{
|
||||
PageMeta_Data_t *m = (PageMeta_Data_t*)__meta;
|
||||
|
||||
while (count--) {
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_DATA;
|
||||
m->c.FTLFlags = 0;
|
||||
m->lba = lba;
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
m->userSeq = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
|
||||
// Next
|
||||
lba++;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Data_UECC(PageMeta_t *__meta)
|
||||
{
|
||||
__meta->c.FTLFlags |= PFLAG_UECC;
|
||||
}
|
||||
|
||||
void SetupMeta_Index(PageMeta_t *__meta, UInt32 ipn)
|
||||
{
|
||||
PageMeta_Idx_t *m = (PageMeta_Idx_t*)__meta;
|
||||
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_IDX;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
m->baseLba = ipn * yaFTL.indexPageRatio;
|
||||
}
|
||||
|
||||
void SetupMeta_Data_BTOC(PageMeta_t *__meta)
|
||||
{
|
||||
PageMeta_BTOC_t *m = (PageMeta_BTOC_t*)__meta;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_BTOC_DATA;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.data.minWeaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.data.minWeaveSeq >> 16);
|
||||
m->maxWeaveSeqAdd = (UInt32)(yaFTL.wrState.weaveSeq - yaFTL.wrState.data.minWeaveSeq);
|
||||
m->__rfu__ = 0xffffffff;
|
||||
}
|
||||
|
||||
void SetupMeta_Index_BTOC(PageMeta_t *__meta)
|
||||
{
|
||||
PageMeta_BTOC_t *m = (PageMeta_BTOC_t*)__meta;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_BTOC_IDX;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.index.minWeaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.index.minWeaveSeq >> 16);
|
||||
m->maxWeaveSeqAdd = (UInt32)(yaFTL.wrState.weaveSeq - yaFTL.wrState.index.minWeaveSeq);
|
||||
m->__rfu__ = 0xffffffff;
|
||||
}
|
||||
|
||||
void SetupMeta_IndexGC(PageMeta_t *__meta, UInt32 count)
|
||||
{
|
||||
PageMeta_Idx_t *m = (PageMeta_Idx_t*)__meta;
|
||||
|
||||
while (count--) {
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_IDX;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
|
||||
// Next
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_DataGC(PageMeta_t *__meta, UInt32 count)
|
||||
{
|
||||
PageMeta_Data_t *m = (PageMeta_Data_t*)__meta;
|
||||
|
||||
while (count--) {
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_DATA;
|
||||
// Don't touch FTLFlags--might have uECC flag
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
// Don't touch LBA or userSeq
|
||||
|
||||
// Next
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Cxt(PageMeta_t *__meta, UInt64 weaveSeq)
|
||||
{
|
||||
PageMeta_Cxt_t *m = (PageMeta_Cxt_t*)__meta;
|
||||
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_CXT;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(weaveSeq >> 16);
|
||||
m->__rfu1__ = 0;
|
||||
m->__rfu2__ = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __YAFTL_META_PPN_H__
|
||||
#define __YAFTL_META_PPN_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
|
||||
|
||||
// PageType defines--
|
||||
#define PAGETYPE_FTL_DATA (AND_SPARE_TYPE_REGION_FTL + 0x00)
|
||||
#define PAGETYPE_FTL_BTOC_DATA (AND_SPARE_TYPE_REGION_FTL + 0x1C)
|
||||
#define PAGETYPE_FTL_BTOC_IDX (AND_SPARE_TYPE_REGION_FTL + 0x1D)
|
||||
#define PAGETYPE_FTL_IDX (AND_SPARE_TYPE_REGION_FTL + 0x1E)
|
||||
#define PAGETYPE_FTL_CXT (AND_SPARE_TYPE_REGION_FTL + 0x1F)
|
||||
|
||||
|
||||
// FTLFlags defines--
|
||||
#define PFLAG_UECC 0x01 // uECC state for data pages (moved by GC and thus re-encoded)
|
||||
|
||||
|
||||
// Must be 16 bytes on PPN
|
||||
|
||||
typedef struct {
|
||||
UInt8 PageType;
|
||||
UInt8 FTLFlags;
|
||||
UInt16 weaveLo;
|
||||
UInt32 weaveHi;
|
||||
} PageMeta_Common_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 __f1;
|
||||
UInt32 __f2;
|
||||
} PageMeta_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 userSeq;
|
||||
UInt32 lba;
|
||||
} PageMeta_Data_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 maxWeaveSeqAdd;
|
||||
UInt32 __rfu__;
|
||||
} PageMeta_BTOC_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt16 __rfu__;
|
||||
UInt16 lbaAdd;
|
||||
UInt32 baseLba;
|
||||
} PageMeta_Idx_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 __rfu1__;
|
||||
UInt32 __rfu2__;
|
||||
} PageMeta_Cxt_t;
|
||||
|
||||
|
||||
typedef UInt64 WeaveSeq_t;
|
||||
|
||||
|
||||
// Setup
|
||||
extern void SetupMeta_Data(PageMeta_t *__meta, UInt32 lba, UInt32 count);
|
||||
extern void SetupMeta_Data_UECC(PageMeta_t *__meta);
|
||||
|
||||
extern void SetupMeta_Index(PageMeta_t *__meta, UInt32 ipn);
|
||||
|
||||
extern void SetupMeta_Data_BTOC(PageMeta_t *__meta);
|
||||
extern void SetupMeta_Index_BTOC(PageMeta_t *__meta);
|
||||
|
||||
extern void SetupMeta_IndexGC(PageMeta_t *__meta, UInt32 count);
|
||||
extern void SetupMeta_DataGC(PageMeta_t *__meta, UInt32 count);
|
||||
|
||||
extern void SetupMeta_Cxt(PageMeta_t *__meta, UInt64 weaveSeq);
|
||||
|
||||
#define META_SET_LBA(meta, foo) do { ((PageMeta_Data_t*)(meta))->lba = (foo); } while (0)
|
||||
#define META_SET_WEAVESEQ(meta) do { (meta)->c.weaveLo = (UInt16)yaFTL.wrState.weaveSeq; (meta)->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16); } while (0)
|
||||
#define META_SET_BTOC_DATA(meta) do { (meta)->c.PageType = PAGETYPE_FTL_BTOC_DATA; } while (0)
|
||||
#define META_SET_IPN_FROM_BTOC(meta, bte) do { ((PageMeta_Idx_t*)(meta))->baseLba = (bte); } while (0)
|
||||
#define BTOC_SET_FROM_IPN(bte, meta) do { (bte) = ((PageMeta_Idx_t*)(meta))->baseLba; } while (0)
|
||||
|
||||
|
||||
// Query
|
||||
#define BTOC_GET_IPN(bte) ((bte) / yaFTL.indexPageRatio)
|
||||
#define META_ARE_FLAGS_FF(meta) ((0xff == (meta)->c.PageType) && (0xff == (meta)->c.FTLFlags))
|
||||
#define META_IS_IDX(meta) (PAGETYPE_FTL_IDX == (meta)->c.PageType)
|
||||
#define META_IS_DATA(meta) (PAGETYPE_FTL_DATA == (meta)->c.PageType)
|
||||
#define META_IS_CXT(meta) (PAGETYPE_FTL_CXT == (meta)->c.PageType)
|
||||
#define META_IS_BTOC_IDX(meta) (PAGETYPE_FTL_BTOC_IDX == (meta)->c.PageType)
|
||||
#define META_IS_BTOC_DATA(meta) (PAGETYPE_FTL_BTOC_DATA == (meta)->c.PageType)
|
||||
#define META_IS_BTOC(meta) ((PAGETYPE_FTL_BTOC_IDX == (meta)->c.PageType) || (PAGETYPE_FTL_BTOC_DATA == ((meta)->c.PageType)))
|
||||
#define META_IS_UECC(meta) ((meta)->c.FTLFlags & PFLAG_UECC)
|
||||
#define META_GET_WEAVESEQ(meta) ((UInt64)(meta)->c.weaveLo | ((UInt64)(meta)->c.weaveHi << 16))
|
||||
#define META_GET_LBA(meta) (((PageMeta_Data_t*)(meta))->lba)
|
||||
#define META_GET_IPN(meta) (((PageMeta_Idx_t*)(meta))->baseLba / yaFTL.indexPageRatio)
|
||||
#define META_GET_IPNRAW(meta) (((PageMeta_Idx_t*)(meta))->baseLba)
|
||||
#define META_GET_ALL_FLAGS(meta) (((UInt32)((meta)->c.FTLFlags) << 8) | (UInt32)((meta)->c.PageType))
|
||||
|
||||
|
||||
|
||||
#endif // __YAFTL_META_PPN_H__
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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 "yaFTL_whoami.h"
|
||||
#include "yaFTL_meta_raw.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "yaFTLTypes.h"
|
||||
|
||||
extern yaFTL_t yaFTL;
|
||||
|
||||
|
||||
void SetupMeta_Data(PageMeta_t *meta, UInt32 lba, UInt32 count)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.data.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.data.block;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
meta->FTLFlags = PAGETYPE_FTL_DATA;
|
||||
meta->lba = lba;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
|
||||
// Next
|
||||
lba++;
|
||||
meta++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Data_UECC(PageMeta_t *meta)
|
||||
{
|
||||
meta->FTLFlags |= PFLAG_UECC;
|
||||
}
|
||||
|
||||
void SetupMeta_Index(PageMeta_t *meta, UInt32 ipn)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.index.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.index.block;
|
||||
}
|
||||
|
||||
meta->FTLFlags = PAGETYPE_FTL_IDX;
|
||||
meta->lba = ipn;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
}
|
||||
|
||||
void SetupMeta_Data_BTOC(PageMeta_t *meta)
|
||||
{
|
||||
meta->FTLFlags = PFLAG_BTOC;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.data.minWeaveSeq;
|
||||
}
|
||||
|
||||
void SetupMeta_Index_BTOC(PageMeta_t *meta)
|
||||
{
|
||||
meta->FTLFlags = PAGETYPE_FTL_IDX | PFLAG_BTOC;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.index.minWeaveSeq;
|
||||
}
|
||||
|
||||
void SetupMeta_IndexGC(PageMeta_t *meta, UInt32 count)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.index.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.index.block;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
meta->FTLFlags = PAGETYPE_FTL_IDX;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
|
||||
// Next
|
||||
meta++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_DataGC(PageMeta_t *meta, UInt32 count)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.data.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.data.block;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
// Or in the page type and clear all but uECC flag
|
||||
meta->FTLFlags = (meta->FTLFlags & PFLAG_UECC) | PAGETYPE_FTL_DATA;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
|
||||
// Next
|
||||
meta++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Cxt(PageMeta_t *meta, UInt64 weaveSeq)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
meta->FTLFlags = PAGETYPE_FTL_CXT;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __YAFTL_META_RAW_H__
|
||||
#define __YAFTL_META_RAW_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
// Page FTLFlags
|
||||
#define PAGETYPE_FTL_IDX 0x04
|
||||
#define PAGETYPE_FTL_DATA 0x10
|
||||
#define PAGETYPE_FTL_CXT 0x20
|
||||
#define PFLAG_BTOC 0x08
|
||||
#define PFLAG_UECC 0x40 // uECC state (moved by GC and thus re-encoded)
|
||||
|
||||
// Must be 12 bytes on raw
|
||||
typedef struct
|
||||
{
|
||||
UInt32 lba; // formerly known as logicalPageNo
|
||||
UInt32 weaveSeq; // formerly known as allocationNo
|
||||
UInt8 __DEPRECATED_seqNo;
|
||||
UInt8 FTLFlags;
|
||||
UInt16 __pad;
|
||||
} PageMeta_t;
|
||||
|
||||
typedef UInt32 WeaveSeq_t;
|
||||
|
||||
|
||||
extern void SetupMeta_Data(PageMeta_t *meta, UInt32 lba, UInt32 count);
|
||||
extern void SetupMeta_Data_UECC(PageMeta_t *meta);
|
||||
|
||||
extern void SetupMeta_Index(PageMeta_t *meta, UInt32 ipn);
|
||||
|
||||
extern void SetupMeta_Data_BTOC(PageMeta_t *meta);
|
||||
extern void SetupMeta_Index_BTOC(PageMeta_t *meta);
|
||||
|
||||
extern void SetupMeta_IndexGC(PageMeta_t *meta, UInt32 count);
|
||||
extern void SetupMeta_DataGC(PageMeta_t *meta, UInt32 count);
|
||||
|
||||
extern void SetupMeta_Cxt(PageMeta_t *meta, UInt64 weaveSeq);
|
||||
|
||||
#define META_SET_LBA(meta, foo) do { (meta)->lba = (foo); } while (0)
|
||||
#define META_SET_WEAVESEQ(meta) do { \
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.index.block) \
|
||||
{ \
|
||||
yaFTL.wrState.weaveSeq++; \
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.index.block; \
|
||||
} \
|
||||
(meta)->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq; \
|
||||
} while(0)
|
||||
#define META_SET_BTOC_DATA(meta) do { (meta)->FTLFlags = PFLAG_BTOC; } while (0)
|
||||
#define META_SET_IPN_FROM_BTOC(meta, bte) do { (meta)->lba = (bte); } while (0)
|
||||
#define BTOC_SET_FROM_IPN(bte, meta) do { (bte) = (meta)->lba; } while (0)
|
||||
|
||||
|
||||
// Query
|
||||
#define BTOC_GET_IPN(bte) (bte)
|
||||
#define META_ARE_FLAGS_FF(meta) (0xff == (meta)->FTLFlags)
|
||||
#define META_IS_IDX(meta) ((meta)->FTLFlags & PAGETYPE_FTL_IDX)
|
||||
#define META_IS_DATA(meta) ((meta)->FTLFlags & PAGETYPE_FTL_DATA)
|
||||
#define META_IS_CXT(meta) ((meta)->FTLFlags & PAGETYPE_FTL_CXT)
|
||||
#define META_IS_BTOC_IDX(meta) (((meta)->FTLFlags & PAGETYPE_FTL_IDX) && ((meta)->FTLFlags & PFLAG_BTOC))
|
||||
#define META_IS_BTOC_DATA(meta) (!((meta)->FTLFlags & PAGETYPE_FTL_IDX) && ((meta)->FTLFlags & PFLAG_BTOC))
|
||||
#define META_IS_BTOC(meta) ((meta)->FTLFlags & PFLAG_BTOC)
|
||||
#define META_IS_UECC(meta) ((meta)->FTLFlags & PFLAG_UECC)
|
||||
#define META_GET_WEAVESEQ(meta) ((meta)->weaveSeq)
|
||||
#define META_GET_LBA(meta) ((meta)->lba)
|
||||
#define META_GET_IPN(meta) ((meta)->lba)
|
||||
#define META_GET_IPNRAW(meta) ((meta)->lba)
|
||||
#define META_GET_ALL_FLAGS(meta) ((UInt32)((meta)->FTLFlags))
|
||||
|
||||
|
||||
|
||||
#endif // __YAFTL_META_RAW_H__
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __YAFTL_WHOAMI_H__
|
||||
#define __YAFTL_WHOAMI_H__
|
||||
|
||||
#define NAND_PPN 1
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,842 @@
|
||||
#include "WMRConfig.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "PPNMiscTypes.h"
|
||||
#include "PPN_FIL.h"
|
||||
#include "FIL.h"
|
||||
|
||||
/* print functions - for now i am keeping it old school */
|
||||
#if (defined (AND_SIMULATOR) && AND_SIMULATOR)
|
||||
#define VFL_ERR_PRINT(x) WMR_PANIC x
|
||||
#else
|
||||
#define VFL_ERR_PRINT(x) WMR_RTL_PRINT(x)
|
||||
#endif
|
||||
#define VFL_WRN_PRINT(x) WMR_RTL_PRINT(x)
|
||||
|
||||
#if defined (VFL_LOG_MSG_ON)
|
||||
#define VFL_LOG_PRINT(x) WMR_DBG_PRINT(x)
|
||||
#else
|
||||
#define VFL_LOG_PRINT(x)
|
||||
#endif
|
||||
#define VFL_INF_MSG_ON (0)
|
||||
#if (defined (VFL_INF_MSG_ON) && VFL_INF_MSG_ON)
|
||||
#define VFL_INF_PRINT(x, y) { if (x) { WMR_RTL_PRINT(y); } }
|
||||
#else
|
||||
#define VFL_INF_PRINT(x, y)
|
||||
#endif
|
||||
|
||||
#define BYTES_PER_PAGE_META (dev->lbas_per_page * dev->lba_meta_bytes_buffer)
|
||||
|
||||
#define PPNMISC_VERIFY_CONVERSION (0)
|
||||
|
||||
#if PPNMISC_VERIFY_CONVERSION
|
||||
static BOOL32
|
||||
ppnMiscTestConversionFunctions
|
||||
(PPN_DeviceInfo * dev);
|
||||
#endif // PPNMISC_VERIFY_CONVERSION
|
||||
|
||||
/*
|
||||
* Name: ppnMiscGetCAUFromBank
|
||||
* Input: bank
|
||||
* Return value: CAU inside a chip enable
|
||||
*/
|
||||
UInt16
|
||||
ppnMiscGetCAUFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank)
|
||||
{
|
||||
return (UInt16)((bank / dev->num_channels) % dev->caus_per_ce);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscGetChannelFromBank
|
||||
* Input: bank
|
||||
* Return value: channel this bank belongs to
|
||||
*/
|
||||
UInt16
|
||||
ppnMiscGetChannelFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank)
|
||||
{
|
||||
return (UInt16)(bank % dev->num_channels);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppnMiscGetCEIdxFromBank
|
||||
* Input: bank
|
||||
* Return value: chip enable index (location) within a channel
|
||||
*/
|
||||
UInt16
|
||||
ppnMiscGetCEIdxFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank)
|
||||
{
|
||||
return (UInt16)((bank / (dev->caus_per_ce * dev->num_channels)) % dev->ces_per_channel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscGetCEFromBank
|
||||
* Input: bank
|
||||
* Return value: physical chip enable value used by the FIL layer
|
||||
*/
|
||||
UInt16
|
||||
ppnMiscGetCEFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank)
|
||||
{
|
||||
UInt16 chip_enable_idx, channel;
|
||||
|
||||
chip_enable_idx = ppnMiscGetCEIdxFromBank(dev, bank);
|
||||
channel = ppnMiscGetChannelFromBank(dev, bank);
|
||||
return dev->chip_enable_table[channel][chip_enable_idx];
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscGetCEIdxFromChipEnable
|
||||
* Input: channel, physical chip enable
|
||||
* Return value: chip enable index inside the specified channel
|
||||
*/
|
||||
UInt16
|
||||
ppnMiscGetCEIdxFromChipEnable
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 channel,
|
||||
UInt16 chip_enable)
|
||||
{
|
||||
UInt16 chip_enable_idx;
|
||||
|
||||
WMR_ASSERT(channel < dev->num_channels);
|
||||
for (chip_enable_idx = 0; chip_enable_idx < dev->ces_per_channel; chip_enable_idx++)
|
||||
{
|
||||
if (dev->chip_enable_table[channel][chip_enable_idx] == chip_enable)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
WMR_ASSERT(chip_enable_idx < dev->ces_per_channel);
|
||||
return chip_enable_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscConvertToPPNPageAddress
|
||||
* Input: cau, block, page offset, slc mode
|
||||
* Return value: physical ppn page address
|
||||
*/
|
||||
UInt32
|
||||
ppnMiscConvertToPPNPageAddress
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 cau,
|
||||
UInt16 block,
|
||||
UInt16 page,
|
||||
BOOL32 slcAddress)
|
||||
{
|
||||
UInt32 ppnPageAddr;
|
||||
|
||||
ppnPageAddr = (UInt32)page;
|
||||
ppnPageAddr |= (UInt32)((UInt32)block << dev->bits_per_page_addr);
|
||||
ppnPageAddr |= (UInt32)((UInt32)cau << (dev->bits_per_page_addr + dev->bits_per_block_addr));
|
||||
ppnPageAddr |= (UInt32)((UInt32)(slcAddress ? 1 : 0) <<
|
||||
(dev->bits_per_page_addr + dev->bits_per_block_addr + dev->bits_per_cau_addr));
|
||||
|
||||
return ppnPageAddr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscConvertPhysicalAddressToCauBlockPage
|
||||
* Input: physcial page address (row address)
|
||||
* Output: cau, block, page offset
|
||||
* Return value: none
|
||||
*/
|
||||
void
|
||||
ppnMiscConvertPhysicalAddressToCauBlockPage
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt32 page,
|
||||
UInt16 *cau,
|
||||
UInt16 *block,
|
||||
UInt16 *page_offset)
|
||||
{
|
||||
UInt32 mask;
|
||||
|
||||
// get page offset
|
||||
mask = (1UL << dev->bits_per_page_addr) - 1;
|
||||
*page_offset = (UInt16)(page & mask);
|
||||
|
||||
// get block
|
||||
mask = (1UL << dev->bits_per_block_addr) - 1;
|
||||
page >>= dev->bits_per_page_addr;
|
||||
*block = (UInt16)(page & mask);
|
||||
|
||||
// get cau
|
||||
mask = (1UL << dev->bits_per_cau_addr) - 1;
|
||||
page >>= dev->bits_per_block_addr;
|
||||
*cau = (UInt16)(page & mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscConvertPhysicalAddressToBankBlockPage
|
||||
* Input: channel, physical chip enable, physcial page address
|
||||
* Output: bank, block, page offset, slc mode
|
||||
* Return value: none
|
||||
*/
|
||||
void
|
||||
ppnMiscConvertPhysicalAddressToBankBlockPage
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 channel,
|
||||
UInt16 chip_enable_idx,
|
||||
UInt32 page,
|
||||
UInt16 *bank,
|
||||
UInt16 *block,
|
||||
UInt16 *page_offset,
|
||||
BOOL32 *slc)
|
||||
{
|
||||
UInt16 cau;
|
||||
UInt32 mask;
|
||||
|
||||
// get page offset
|
||||
mask = (1UL << dev->bits_per_page_addr) - 1;
|
||||
*page_offset = (UInt16)(page & mask);
|
||||
|
||||
// get block
|
||||
mask = (1UL << dev->bits_per_block_addr) - 1;
|
||||
page >>= dev->bits_per_page_addr;
|
||||
*block = (UInt16)(page & mask);
|
||||
|
||||
// get cau
|
||||
mask = (1UL << dev->bits_per_cau_addr) - 1;
|
||||
page >>= dev->bits_per_block_addr;
|
||||
cau = (UInt16)(page & mask);
|
||||
|
||||
// get SLC bit
|
||||
page >>= dev->bits_per_cau_addr;
|
||||
*slc = (page & 1) ? TRUE32 : FALSE32;
|
||||
|
||||
*bank = ((chip_enable_idx * dev->num_channels * dev->caus_per_ce) +
|
||||
(cau * dev->num_channels) + channel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscSingleOperation
|
||||
* Description: this function prepares a command for a low level operation.
|
||||
* Input: command type, bank, block, page offset, slc mode, data pointer,
|
||||
* meta pointer
|
||||
* data pointer, meta pointer
|
||||
* Return value: operation status
|
||||
*/
|
||||
PPNStatusType
|
||||
ppnMiscSingleOperation
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct * command,
|
||||
PPNCommand command_type,
|
||||
PPNOptions options,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc,
|
||||
void *data,
|
||||
void *meta)
|
||||
{
|
||||
UInt16 cau = 0, channel = 0, i = 0, chip_enable_idx = 0;
|
||||
UInt8 status;
|
||||
UInt32 row_addr;
|
||||
|
||||
channel = ppnMiscGetChannelFromBank(dev, bank);
|
||||
cau = ppnMiscGetCAUFromBank(dev, bank);
|
||||
chip_enable_idx = ppnMiscGetCEIdxFromBank(dev, bank);
|
||||
|
||||
WMR_MEMSET(command, 0, sizeof(PPNCommandStruct));
|
||||
|
||||
command->num_pages = 1;
|
||||
command->lbas = dev->lbas_per_page;
|
||||
command->command = command_type;
|
||||
command->options = options;
|
||||
command->mem_buffers[0].data = data;
|
||||
command->mem_buffers[0].meta = meta;
|
||||
command->mem_buffers[0].num_of_lbas = dev->lbas_per_page; // change if this is a small read
|
||||
row_addr = ppnMiscConvertToPPNPageAddress(dev, cau, block, page_offset, slc);
|
||||
|
||||
switch (command_type)
|
||||
{
|
||||
case PPN_COMMAND_READ:
|
||||
{
|
||||
command->entry[0].addr.row = row_addr;
|
||||
command->entry[0].addr.column = 0;
|
||||
command->entry[0].addr.length =
|
||||
(dev->lba_meta_bytes_buffer + dev->main_bytes_per_lba) * dev->lbas_per_page;
|
||||
command->mem_index[0].offset = 0;
|
||||
command->mem_index[0].idx = 0; // change for sub page reads
|
||||
command->entry[0].lbas = dev->lbas_per_page; // change for sub page reads
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef AND_READONLY
|
||||
case PPN_COMMAND_PROGRAM:
|
||||
case PPN_COMMAND_ERASE:
|
||||
{
|
||||
command->entry[0].addr.row = row_addr;
|
||||
command->mem_index[0].offset = 0;
|
||||
command->mem_index[0].idx = 0;
|
||||
command->entry[0].lbas = dev->lbas_per_page;
|
||||
break;
|
||||
}
|
||||
#endif // AND_READONLY
|
||||
|
||||
default:
|
||||
{
|
||||
command->entry[0].addr.row = row_addr;
|
||||
command->mem_index[0].offset = 0;
|
||||
command->mem_index[0].idx = 0;
|
||||
command->entry[0].lbas = dev->lbas_per_page;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
command->entry[0].ceIdx = chip_enable_idx;
|
||||
for (i = 0; i < dev->ces_per_channel; i++)
|
||||
{
|
||||
command->ceInfo[i].ce = dev->chip_enable_table[channel][i];
|
||||
command->ceInfo[i].pages = 0;
|
||||
}
|
||||
command->ceInfo[chip_enable_idx].pages = 1;
|
||||
|
||||
command->context.device_info = NULL;
|
||||
command->context.handle = NULL;
|
||||
command->context.bus_num = channel;
|
||||
|
||||
dev->fil->PerformCommandList(&command, 1);
|
||||
status = command->page_status_summary;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscSingleLbaRead
|
||||
* Description: this function prepares a command for a low level single LBA read.
|
||||
* Input: command type, ce, cau, block, page offset, slc mode, data pointer,
|
||||
* meta pointer
|
||||
* Return value: operation status
|
||||
*/
|
||||
PPNStatusType
|
||||
ppnMiscSingleLbaRead
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct * command,
|
||||
PPNCommand command_type,
|
||||
PPNOptions options,
|
||||
UInt16 ce,
|
||||
UInt16 cau,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
UInt8 lba_offset,
|
||||
BOOL32 slc,
|
||||
void *data,
|
||||
void *meta)
|
||||
{
|
||||
UInt16 channel = 0, i = 0, chip_enable_idx = 0;
|
||||
UInt8 status;
|
||||
UInt32 row_addr;
|
||||
|
||||
chip_enable_idx = ce % dev->ces_per_channel;
|
||||
channel = ce / dev->ces_per_channel;
|
||||
|
||||
WMR_MEMSET(command, 0, sizeof(PPNCommandStruct));
|
||||
|
||||
command->num_pages = 1;
|
||||
command->lbas = 1;
|
||||
command->command = command_type;
|
||||
command->options = options;
|
||||
command->mem_buffers[0].data = data;
|
||||
command->mem_buffers[0].meta = meta;
|
||||
command->mem_buffers[0].num_of_lbas = 1;
|
||||
row_addr = ppnMiscConvertToPPNPageAddress(dev, cau, block, page_offset, slc);
|
||||
|
||||
switch (command_type)
|
||||
{
|
||||
case PPN_COMMAND_READ:
|
||||
{
|
||||
command->entry[0].addr.row = row_addr;
|
||||
command->entry[0].addr.column = lba_offset * (dev->main_bytes_per_lba + dev->lba_meta_bytes_buffer);
|
||||
command->entry[0].addr.length =
|
||||
(dev->lba_meta_bytes_buffer + dev->main_bytes_per_lba);
|
||||
command->mem_index[0].offset = 0;
|
||||
command->mem_index[0].idx = command->mem_buffers_count;
|
||||
command->entry[0].lbas = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] currently only read supported: (l:%d)\n"), __LINE__));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
command->entry[0].ceIdx = chip_enable_idx;
|
||||
for (i = 0; i < dev->ces_per_channel; i++)
|
||||
{
|
||||
command->ceInfo[i].ce = dev->chip_enable_table[channel][i];
|
||||
command->ceInfo[i].pages = 0;
|
||||
}
|
||||
command->ceInfo[chip_enable_idx].pages = 1;
|
||||
|
||||
command->context.device_info = NULL;
|
||||
command->context.handle = NULL;
|
||||
command->context.bus_num = channel;
|
||||
|
||||
dev->fil->PerformCommandList(&command, 1);
|
||||
status = command->page_status_summary;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscFillDevStruct
|
||||
* Description: this function fills the device information struct for vfl and fpart.
|
||||
* Input: fil function struct
|
||||
* Return value: none
|
||||
*/
|
||||
void
|
||||
ppnMiscFillDevStruct
|
||||
(PPN_DeviceInfo * dev,
|
||||
LowFuncTbl *fil)
|
||||
{
|
||||
UInt16 channel, chip_enable_idx;
|
||||
|
||||
dev->fil = fil;
|
||||
dev->num_channels = fil->GetDeviceInfo(AND_DEVINFO_NUM_OF_CHANNELS);
|
||||
dev->ces_per_channel = fil->GetDeviceInfo(AND_DEVINFO_NUM_OF_CES_PER_CHANNEL);
|
||||
dev->caus_per_ce = fil->GetDeviceInfo(AND_DEVINFO_CAUS_PER_CE);
|
||||
dev->blocks_per_cau = fil->GetDeviceInfo(AND_DEVINFO_BLOCKS_PER_CAU);
|
||||
dev->pages_per_block_slc = fil->GetDeviceInfo(AND_DEVINFO_SLC_PAGES_PER_BLOCK);
|
||||
dev->pages_per_block_mlc = fil->GetDeviceInfo(AND_DEVINFO_MLC_PAGES_PER_BLOCK);
|
||||
dev->f_match_oddeven_blocks = (BOOL32)fil->GetDeviceInfo(AND_DEVINFO_MATCH_ODDEVEN_CAUS);
|
||||
dev->bits_per_cau_addr = fil->GetDeviceInfo(AND_DEVINFO_BITS_PER_CAU_ADDRESS);
|
||||
dev->bits_per_page_addr = fil->GetDeviceInfo(AND_DEVINFO_BITS_PER_PAGE_ADDRESS);
|
||||
dev->bits_per_block_addr = fil->GetDeviceInfo(AND_DEVINFO_BITS_PER_BLOCK_ADDRESS);
|
||||
dev->main_bytes_per_page = fil->GetDeviceInfo(AND_DEVINFO_BYTES_PER_PAGE);
|
||||
dev->num_of_banks = dev->num_channels * dev->ces_per_channel * dev->caus_per_ce;
|
||||
dev->lbas_per_page = fil->GetDeviceInfo(AND_DEVINFO_FIL_LBAS_PER_PAGE);
|
||||
dev->main_bytes_per_lba = dev->main_bytes_per_page / dev->lbas_per_page;
|
||||
dev->lba_meta_bytes_buffer = fil->GetDeviceInfo(AND_DEVINFO_FIL_META_BUFFER_BYTES);
|
||||
dev->lba_meta_bytes_valid = fil->GetDeviceInfo(AND_DEVINFO_FIL_META_VALID_BYTES);
|
||||
dev->max_pages_in_prep_per_ce = fil->GetDeviceInfo(AND_DEVINFO_FIL_PREP_BUFFER_ENTRIES);
|
||||
// dev->f_match_oddeven_blocks = (fil->GetDeviceInfo(AND_DEVINFO_FIL_MATCH_ODD_EVEN_BLKS) ?
|
||||
// TRUE32 : FALSE32);
|
||||
|
||||
// WMR_PRINT(ALWAYS, "num_of_banks = %d (num_channels = %d, ces_per_channel = %d, caus_per_ce = %d\n",
|
||||
// dev->num_of_banks, dev->num_channels, dev->ces_per_channel, dev->caus_per_ce);
|
||||
|
||||
dev->pages_per_sublk = dev->num_of_banks * dev->pages_per_block_mlc;
|
||||
for (channel = 0; channel < dev->num_channels; channel++)
|
||||
{
|
||||
for (chip_enable_idx = 0; chip_enable_idx < dev->ces_per_channel; chip_enable_idx++)
|
||||
{
|
||||
PPNChipEnableStruct chip_enable_struct;
|
||||
UInt32 size;
|
||||
chip_enable_struct.channel = channel;
|
||||
chip_enable_struct.chip_enable_idx = chip_enable_idx;
|
||||
FIL_GetStruct(AND_STRUCT_FIL_GET_CE_INFO, &chip_enable_struct, &size);
|
||||
dev->chip_enable_table[channel][chip_enable_idx] = chip_enable_struct.physical_chip_enable;
|
||||
}
|
||||
}
|
||||
|
||||
#if PPNMISC_VERIFY_CONVERSION
|
||||
// debug code - verify that the conversion code works correctly
|
||||
ppnMiscTestConversionFunctions(dev);
|
||||
#endif // PPNMISC_VERIFY_CONVERSION
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscIsBlockGood
|
||||
* Description: this function takes the bad block table bitmap and checks if a
|
||||
* block is initally marked bad or not.
|
||||
* Input: bad block table bitmap (as read from the PPN device), block
|
||||
* Return value: none
|
||||
*/
|
||||
BOOL32
|
||||
ppnMiscIsBlockGood
|
||||
(UInt8 *bbt,
|
||||
UInt16 block)
|
||||
{
|
||||
UInt16 byte;
|
||||
UInt8 bit;
|
||||
|
||||
byte = block >> 3;
|
||||
bit = 0x80 >> (block & 0x0007);
|
||||
return bbt[byte] & bit ? TRUE32 : FALSE32;
|
||||
}
|
||||
|
||||
#ifndef AND_READONLY
|
||||
|
||||
BOOL32
|
||||
ppnMiscTestSpecialBlock
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct * command,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt8 spareType)
|
||||
{
|
||||
// try the block (erase, program, read) twice
|
||||
UInt16 page_offset, i;
|
||||
Buffer *buf = BUF_Get(BUF_MAIN_AND_SPARE);
|
||||
BOOL32 slc = TRUE32;
|
||||
BOOL32 pages;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
PPNStatusType status;
|
||||
|
||||
// alternate between slc and mlc
|
||||
slc = (slc ? FALSE32 : TRUE32);
|
||||
pages = (slc ? dev->pages_per_block_slc : dev->pages_per_block_mlc);
|
||||
|
||||
// erase
|
||||
status = ppnMiscSingleOperation(dev, command, PPN_COMMAND_ERASE, PPN_OPTIONS_IGNORE_BAD_BLOCK,
|
||||
bank, block, 0, slc, NULL, NULL);
|
||||
if (status & (PPN_ERASE_STATUS_RETIRE | PPN_ERASE_STATUS_FAIL))
|
||||
{
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:WRN] testing special block - failed erasing (0x%X, 0x%X) (l:%d)\n"), bank,
|
||||
block, __LINE__));
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
// program
|
||||
for (page_offset = 0; page_offset < pages; page_offset++)
|
||||
{
|
||||
WMR_MEMSET(buf->pData, (UInt8)page_offset, dev->main_bytes_per_page);
|
||||
WMR_MEMSET(buf->pSpare, spareType, BYTES_PER_PAGE_META);
|
||||
status = ppnMiscSingleOperation(dev, command, PPN_COMMAND_PROGRAM, PPN_NO_OPTIONS,
|
||||
bank, block, page_offset, slc, buf->pData, buf->pSpare);
|
||||
if (status & (PPN_PROGRAM_STATUS_FAIL))
|
||||
{
|
||||
VFL_WRN_PRINT((TEXT(
|
||||
"PPNMISC:WRN] testing special block - failed programming (0x%X, 0x%X, 0x%X) (l:%d)\n"),
|
||||
bank, block,
|
||||
page_offset, __LINE__));
|
||||
goto return_error;
|
||||
}
|
||||
}
|
||||
// verify
|
||||
for (page_offset = 0; page_offset < pages; page_offset++)
|
||||
{
|
||||
WMR_MEMSET(buf->pData, 0, dev->main_bytes_per_page);
|
||||
WMR_MEMSET(buf->pSpare, 0, BYTES_PER_PAGE_META);
|
||||
status = ppnMiscSingleOperation(dev, command, PPN_COMMAND_READ, PPN_NO_OPTIONS, bank, block, page_offset,
|
||||
slc, buf->pData, buf->pSpare);
|
||||
if (status & (PPN_READ_STATUS_INVALID_DATA | PPN_READ_STATUS_REFRESH | PPN_READ_STATUS_RETIRE))
|
||||
{
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:WRN] testing special block - failed reading (0x%X, 0x%X, 0x%X) (l:%d)\n"),
|
||||
bank, block, page_offset, __LINE__));
|
||||
goto return_error;
|
||||
}
|
||||
if (buf->pData[0] != (UInt8)page_offset || buf->pSpare[0] != spareType)
|
||||
{
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:WRN] testing special block - failed verifying (0x%X, 0x%X, 0x%X) (l:%d)\n"),
|
||||
bank, block, page_offset, __LINE__));
|
||||
goto return_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
BUF_Release(buf);
|
||||
return TRUE32;
|
||||
|
||||
return_error:
|
||||
BUF_Release(buf);
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
#endif // AND_READONLY
|
||||
|
||||
BOOL32
|
||||
ppnMiscAddPhysicalAddressToCommandStructure
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 channel,
|
||||
UInt16 chip_enable_idx,
|
||||
UInt16 cau,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc,
|
||||
UInt8 pba_offset,
|
||||
UInt8 pba_count,
|
||||
UInt8 mem_index,
|
||||
UInt16 mem_offset)
|
||||
{
|
||||
UInt16 idx = 0;
|
||||
UInt32 page_address = 0;
|
||||
PPNCommandStruct *command;
|
||||
|
||||
page_address = ppnMiscConvertToPPNPageAddress(dev, cau, block, page_offset, FALSE32);
|
||||
command = commands[channel];
|
||||
// check for buffer overflow
|
||||
if ((command->num_pages >= PPN_MAX_PAGES) ||
|
||||
(command->ceInfo[chip_enable_idx].pages >= PPN_MAX_PAGES_PER_CE) ||
|
||||
(command->ceInfo[chip_enable_idx].pages >= dev->max_pages_in_prep_per_ce))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
// use idx as a temp variable for index in this specific channel
|
||||
idx = commands[channel]->num_pages;
|
||||
command->entry[idx].ceIdx = chip_enable_idx;
|
||||
switch (command->command)
|
||||
{
|
||||
case PPN_COMMAND_READ:
|
||||
{
|
||||
command->entry[idx].addr.row = page_address;
|
||||
command->entry[idx].addr.column = pba_offset * (dev->main_bytes_per_lba + dev->lba_meta_bytes_buffer);
|
||||
command->entry[idx].addr.length = pba_count * (dev->main_bytes_per_lba + dev->lba_meta_bytes_buffer);
|
||||
command->mem_index[idx].offset = mem_offset;
|
||||
command->mem_index[idx].idx = mem_index;
|
||||
command->entry[idx].lbas = pba_count;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef AND_READONLY
|
||||
case PPN_COMMAND_PROGRAM:
|
||||
case PPN_COMMAND_ERASE:
|
||||
{
|
||||
command->entry[idx].addr.row = page_address;
|
||||
command->mem_index[idx].offset = mem_offset;
|
||||
command->mem_index[idx].idx = mem_index;
|
||||
command->entry[idx].lbas = dev->lbas_per_page;
|
||||
break;
|
||||
}
|
||||
#endif // AND_READONLY
|
||||
|
||||
default:
|
||||
{
|
||||
command->entry[idx].addr.row = page_address;
|
||||
command->mem_index[idx].offset = mem_offset;
|
||||
command->mem_index[idx].idx = mem_index;
|
||||
command->entry[idx].lbas = dev->lbas_per_page;
|
||||
break;
|
||||
}
|
||||
}
|
||||
commands[channel]->lbas += command->entry[idx].lbas;
|
||||
command->num_pages++;
|
||||
|
||||
// use idx as a temp variable for index in prep buffer
|
||||
command->ceInfo[chip_enable_idx].pages++;
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscAddMemoryToCommandStructure
|
||||
* Output: pointer to commands structure
|
||||
* Input: command type, data pointer, meta pointer.
|
||||
* Return value: TRUE32 for success otherwise FALSE32
|
||||
*/
|
||||
BOOL32
|
||||
ppnMiscAddMemoryToCommandStructure
|
||||
(PPN_DeviceInfo *dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 num_of_command_structs,
|
||||
void *data,
|
||||
void *meta,
|
||||
UInt8 num_of_lbas)
|
||||
{
|
||||
UInt16 struct_idx;
|
||||
|
||||
for (struct_idx = 0; struct_idx < num_of_command_structs; struct_idx++)
|
||||
{
|
||||
PPNCommandStruct *command = commands[struct_idx];
|
||||
PPNMemoryEntry *mem = &command->mem_buffers[command->mem_buffers_count];
|
||||
|
||||
if (command->mem_buffers_count >= PPN_MAX_MEM_BUFFERS)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
mem->data = data;
|
||||
mem->meta = meta;
|
||||
mem->num_of_lbas = num_of_lbas;
|
||||
command->mem_buffers_count++;
|
||||
}
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name: ppnMiscInitCommandStructure
|
||||
* Output: pointer to commands structure
|
||||
* Input: command type, data pointer, meta pointer.
|
||||
* Return value: none
|
||||
*/
|
||||
void
|
||||
ppnMiscInitCommandStructure
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 num_of_command_structs,
|
||||
PPNCommand command,
|
||||
PPNOptions options)
|
||||
{
|
||||
UInt16 i, j;
|
||||
|
||||
for (i = 0; i < num_of_command_structs; i++)
|
||||
{
|
||||
WMR_MEMSET(commands[i], 0, sizeof(PPNCommandStruct));
|
||||
// initilaze the command structure fields
|
||||
commands[i]->options = options;
|
||||
commands[i]->num_pages = 0;
|
||||
commands[i]->lbas = 0;
|
||||
commands[i]->command = command;
|
||||
commands[i]->mem_buffers[0].data = NULL;
|
||||
commands[i]->mem_buffers[0].meta = NULL;
|
||||
commands[i]->mem_buffers_count = 0;
|
||||
for (j = 0; j < dev->ces_per_channel; j++)
|
||||
{
|
||||
commands[i]->ceInfo[j].ce = dev->chip_enable_table[i][j];
|
||||
commands[i]->ceInfo[j].pages = 0;
|
||||
}
|
||||
commands[i]->context.device_info = NULL;
|
||||
commands[i]->context.handle = NULL;
|
||||
commands[i]->context.bus_num = i;
|
||||
}
|
||||
}
|
||||
|
||||
#if PPNMISC_VERIFY_CONVERSION
|
||||
|
||||
static BOOL32
|
||||
_verifyAnAddress
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc)
|
||||
{
|
||||
UInt16 chip_enable_idx, channel, cau;
|
||||
UInt32 page_address = 0, line_failed = 0;
|
||||
UInt16 temp_bank, temp_block, temp_page_offset;
|
||||
BOOL32 temp_slc;
|
||||
|
||||
// convert to a physical address
|
||||
cau = ppnMiscGetCAUFromBank(dev, bank);
|
||||
if (!(cau < dev->caus_per_ce))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
page_address = ppnMiscConvertToPPNPageAddress(dev, cau, block, page_offset, slc);
|
||||
chip_enable_idx = ppnMiscGetCEIdxFromBank(dev, bank);
|
||||
if (!(chip_enable_idx < dev->ces_per_channel))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
channel = ppnMiscGetChannelFromBank(dev, bank);
|
||||
if (!(channel < dev->num_channels))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
// convert back
|
||||
ppnMiscConvertPhysicalAddressToBankBlockPage(dev, channel, chip_enable_idx, page_address,
|
||||
&temp_bank, &temp_block, &temp_page_offset, &temp_slc);
|
||||
if (!((temp_bank == bank) && (temp_block == block) && (temp_page_offset == page_offset) && (slc == temp_slc)))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
|
||||
return_error:
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] fail address conversion: (l:%d)\n"), line_failed));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] bank:0x%X, block:0x%X, page_offset:0x%X, slc:0x%X\n"),
|
||||
bank, block, page_offset, slc));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] channel:0x%X, chip_enable_idx:0x%X, cau:0x%X\n"),
|
||||
channel, chip_enable_idx, cau));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] temp_bank:0x%X, temp_block:0x%X, temp_page_offset:0x%X, temp_slc:0x%X\n"),
|
||||
temp_bank, temp_block, temp_page_offset, temp_slc));
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
static BOOL32
|
||||
ppnMiscTestConversionFunctions
|
||||
(PPN_DeviceInfo * dev)
|
||||
{
|
||||
UInt16 bank, block, page_offset;
|
||||
UInt32 counter = 0;
|
||||
|
||||
for (bank = 0; bank < dev->num_of_banks; bank++)
|
||||
{
|
||||
for (block = 0; block < dev->blocks_per_cau; block++)
|
||||
{
|
||||
for (page_offset = 0; page_offset < dev->pages_per_block_mlc; page_offset++)
|
||||
{
|
||||
counter++;
|
||||
if (!(_verifyAnAddress(dev, bank, block, page_offset, TRUE32)))
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] fail address conversion test: (l:%d)\n"), __LINE__));
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
for (page_offset = 0; page_offset < dev->pages_per_block_slc; page_offset++)
|
||||
{
|
||||
if (!(_verifyAnAddress(dev, bank, block, page_offset, TRUE32)))
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] fail address conversion test: (l:%d)\n"), __LINE__));
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
#endif // PPNMISC_VERIFY_CONVERSION
|
||||
|
||||
void
|
||||
ppnMiscReorderCommandStruct
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 num_of_command_structs,
|
||||
PPNReorderStruct *reorder)
|
||||
{
|
||||
UInt16 channel;
|
||||
|
||||
// if there is only one ce per channel no need to reorder
|
||||
if (dev->ces_per_channel == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if !AND_READONLY
|
||||
if (PPN_COMMAND_PROGRAM == (*commands)->command)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif // !AND_READONLY
|
||||
|
||||
for (channel = 0; channel < num_of_command_structs; channel++)
|
||||
{
|
||||
PPNCommandStruct *command = commands[channel];
|
||||
UInt16 ce, page_idx;
|
||||
UInt16 ce_page_count[PPN_MAX_CES_PER_BUS] = {0};
|
||||
|
||||
if (1 >= command->num_pages)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (page_idx = 0; page_idx < command->num_pages; page_idx++)
|
||||
{
|
||||
const PPNCommandEntry *entry = &command->entry[page_idx];
|
||||
const PPNMemoryIndex *memIndex = &command->mem_index[page_idx];
|
||||
reorder->entry[entry->ceIdx][ce_page_count[entry->ceIdx]] = *entry;
|
||||
reorder->mem_index[entry->ceIdx][ce_page_count[entry->ceIdx]] = *memIndex;
|
||||
ce_page_count[entry->ceIdx]++;
|
||||
}
|
||||
|
||||
page_idx = 0;
|
||||
for (ce = 0; ce < dev->ces_per_channel; ce++)
|
||||
{
|
||||
const PPNCommandEntry *entry = reorder->entry[ce];
|
||||
const PPNMemoryIndex *memIndex = reorder->mem_index[ce];
|
||||
WMR_MEMCPY(&command->entry[page_idx], entry, ce_page_count[ce] * sizeof(*entry));
|
||||
WMR_MEMCPY(&command->mem_index[page_idx], memIndex, ce_page_count[ce] * sizeof(*memIndex));
|
||||
command->ceInfo[ce].offset = page_idx;
|
||||
page_idx += ce_page_count[ce];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
#ifndef _PPN_MISC_TYPES_H_
|
||||
#define _PPN_MISC_TYPES_H_
|
||||
|
||||
#include "WMRConfig.h"
|
||||
#include "PPN_FIL.h"
|
||||
#include "FIL.h"
|
||||
|
||||
#define PPN_SPECIAL_BLOCK_LIMIT(dev) ((dev)->blocks_per_cau - (((dev)->blocks_per_cau * 5) / 100))
|
||||
|
||||
/* PPNVFL internal structures */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 num_channels;
|
||||
UInt32 ces_per_channel;
|
||||
UInt32 caus_per_ce;
|
||||
UInt32 num_of_banks;
|
||||
UInt32 blocks_per_cau;
|
||||
UInt32 pages_per_block_slc;
|
||||
UInt32 pages_per_block_mlc;
|
||||
UInt32 bits_per_cau_addr;
|
||||
UInt32 bits_per_page_addr;
|
||||
UInt32 bits_per_block_addr;
|
||||
UInt32 main_bytes_per_page;
|
||||
UInt32 main_bytes_per_lba;
|
||||
UInt32 pages_per_sublk;
|
||||
UInt32 lbas_per_page;
|
||||
UInt32 lba_meta_bytes_valid;
|
||||
UInt32 lba_meta_bytes_buffer;
|
||||
UInt32 max_pages_in_prep_per_ce;
|
||||
BOOL32 f_match_oddeven_blocks;
|
||||
UInt16 chip_enable_table[4][4]; // up to 4 channels and up to 4 chip enables per channel
|
||||
LowFuncTbl *fil;
|
||||
} PPN_DeviceInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PPNCommandEntry entry[PPN_MAX_CES_PER_BUS][PPN_MAX_PAGES_PER_CE];
|
||||
PPNMemoryIndex mem_index[PPN_MAX_CES_PER_BUS][PPN_MAX_PAGES_PER_CE];
|
||||
} PPNReorderStruct;
|
||||
|
||||
UInt16 ppnMiscGetCAUFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank);
|
||||
UInt16 ppnMiscGetChannelFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank);
|
||||
UInt16 ppnMiscGetCEIdxFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank);
|
||||
UInt16 ppnMiscGetCEFromBank
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank);
|
||||
UInt16 ppnMiscGetCEIdxFromChipEnable
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 channel,
|
||||
UInt16 chip_enable);
|
||||
UInt32 ppnMiscConvertToPPNPageAddress
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 cau,
|
||||
UInt16 block,
|
||||
UInt16 page,
|
||||
BOOL32 slcAddress);
|
||||
void ppnMiscConvertPhysicalAddressToBankBlockPage
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 channel,
|
||||
UInt16 chip_enable_idx,
|
||||
UInt32 page,
|
||||
UInt16 *bank,
|
||||
UInt16 *block,
|
||||
UInt16 *page_offset,
|
||||
BOOL32 *slc);
|
||||
void ppnMiscConvertPhysicalAddressToCauBlockPage
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt32 page,
|
||||
UInt16 *cau,
|
||||
UInt16 *block,
|
||||
UInt16 *page_offset);
|
||||
PPNStatusType ppnMiscSingleOperation
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct * command,
|
||||
PPNCommand command_type,
|
||||
PPNOptions options,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc,
|
||||
void *data,
|
||||
void *meta);
|
||||
void ppnMiscFillDevStruct
|
||||
(PPN_DeviceInfo * dev,
|
||||
LowFuncTbl *fil);
|
||||
BOOL32 ppnMiscIsBlockGood
|
||||
(UInt8 *bbt,
|
||||
UInt16 block);
|
||||
BOOL32
|
||||
ppnMiscAddPhysicalAddressToCommandStructure
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 channel,
|
||||
UInt16 chip_enable_idx,
|
||||
UInt16 cau,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc,
|
||||
UInt8 pba_offset,
|
||||
UInt8 pba_count,
|
||||
UInt8 mem_index,
|
||||
UInt16 mem_offset);
|
||||
void
|
||||
ppnMiscInitCommandStructure
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 num_of_command_structs,
|
||||
PPNCommand command,
|
||||
PPNOptions options);
|
||||
BOOL32
|
||||
ppnMiscAddMemoryToCommandStructure
|
||||
(PPN_DeviceInfo *dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 num_of_command_structs,
|
||||
void *data,
|
||||
void *meta,
|
||||
UInt8 num_of_lbas);
|
||||
|
||||
#ifndef AND_READONLY
|
||||
BOOL32
|
||||
ppnMiscTestSpecialBlock
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct * command,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt8 spareType);
|
||||
#endif // AND_READONLY
|
||||
|
||||
void
|
||||
ppnMiscReorderCommandStruct
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct **commands,
|
||||
UInt16 num_of_command_structs,
|
||||
PPNReorderStruct *reorder);
|
||||
|
||||
PPNStatusType
|
||||
ppnMiscSingleLbaRead
|
||||
(PPN_DeviceInfo * dev,
|
||||
PPNCommandStruct * command,
|
||||
PPNCommand command_type,
|
||||
PPNOptions options,
|
||||
UInt16 ce,
|
||||
UInt16 cau,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
UInt8 lba_offset,
|
||||
BOOL32 slc,
|
||||
void *data,
|
||||
void *meta);
|
||||
|
||||
#endif /* _PPN_MISC_TYPES_H_ */
|
||||
@@ -0,0 +1,399 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* COMPONENT : Rainbow */
|
||||
/* MODULE : Virtual Flash Layer */
|
||||
/* NAME : VFL Buffer Management */
|
||||
/* FILE : VFLBuffer.c */
|
||||
/* PURPOSE : This file contains routines for managing buffers which */
|
||||
/* whimory uses. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* COPYRIGHT 2003-2005 SAMSUNG ELECTRONICS CO., LTD. */
|
||||
/* ALL RIGHTS RESERVED */
|
||||
/* */
|
||||
/* Permission is hereby granted to licensees of Samsung Electronics */
|
||||
/* Co., Ltd. products to use or abstract this computer program for the */
|
||||
/* sole purpose of implementing a product based on Samsung */
|
||||
/* Electronics Co., Ltd. products. No other rights to reproduce, use, */
|
||||
/* or disseminate this computer program, whether in part or in whole, */
|
||||
/* are granted. */
|
||||
/* */
|
||||
/* Samsung Electronics Co., Ltd. makes no representation or warranties */
|
||||
/* with respect to the performance of this computer program, and */
|
||||
/* specifically disclaims any responsibility for any damages, */
|
||||
/* special or consequential, connected with the use of this program. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* REVISION HISTORY */
|
||||
/* */
|
||||
/* 13-JUL-2005 [Jaesung Jung] : separate from vfl.c & reorganize code */
|
||||
/* 06-SEP-2005 [Jaesung Jung] : fix from code inspection */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Header file inclusions */
|
||||
/*****************************************************************************/
|
||||
#include "WMRConfig.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "VFLBuffer.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Debug Print #defines */
|
||||
/*****************************************************************************/
|
||||
#if (defined(AND_SIMULATOR) && AND_SIMULATOR)
|
||||
#define BUF_ERR_PRINT(x) { WMR_RTL_PRINT(x); WMR_PANIC(); }
|
||||
#else
|
||||
#define BUF_ERR_PRINT(x) WMR_RTL_PRINT(x)
|
||||
#endif
|
||||
#define BUF_RTL_PRINT(x) WMR_RTL_PRINT(x)
|
||||
|
||||
#if defined (BUF_LOG_MSG_ON)
|
||||
#define BUF_LOG_PRINT(x) WMR_DBG_PRINT(x)
|
||||
#else
|
||||
#define BUF_LOG_PRINT(x)
|
||||
#endif
|
||||
|
||||
#if defined (BUF_INF_MSG_ON)
|
||||
#define BUF_INF_PRINT(x) WMR_DBG_PRINT(x)
|
||||
#else
|
||||
#define BUF_INF_PRINT(x)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Static variables definitions */
|
||||
/*****************************************************************************/
|
||||
BUFCxt *pstBufferCxt = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt16 wBytesPerPage; /* bytes per page (main) */
|
||||
UInt16 wBytesPerPageMeta;
|
||||
} VFLBufferDeviceInfo;
|
||||
static VFLBufferDeviceInfo stVFLBufferDeviceInfo;
|
||||
|
||||
#define BYTES_PER_PAGE (stVFLBufferDeviceInfo.wBytesPerPage)
|
||||
#define BYTES_PER_PAGE_META (stVFLBufferDeviceInfo.wBytesPerPageMeta)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code Implementation */
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* NAME */
|
||||
/* BUF_Init */
|
||||
/* DESCRIPTION */
|
||||
/* This function initializes the buffer manager & the buffer pool. */
|
||||
/* PARAMETERS */
|
||||
/* none */
|
||||
/* RETURN VALUES */
|
||||
/* BUF_SUCCESS */
|
||||
/* BUF_Init is completed. */
|
||||
/* BUF_CRITICAL_ERROR */
|
||||
/* BUF_Init is failed */
|
||||
/* NOTES */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
Int32
|
||||
BUF_Init(UInt16 wDataBytesPerPage, UInt16 wMetaBytesPerPage, UInt16 wNumberOfBuffers)
|
||||
{
|
||||
UInt32 nBufIdx;
|
||||
Buffer *pBufIdx;
|
||||
|
||||
if (pstBufferCxt != NULL)
|
||||
{
|
||||
return BUF_SUCCESS;
|
||||
}
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF: IN] ++BUF_Init(void)\n")));
|
||||
|
||||
stVFLBufferDeviceInfo.wBytesPerPage = wDataBytesPerPage;
|
||||
stVFLBufferDeviceInfo.wBytesPerPageMeta = wMetaBytesPerPage;
|
||||
|
||||
/* Initialize buffer context */
|
||||
pstBufferCxt = (BUFCxt *)WMR_MALLOC(sizeof(BUFCxt));
|
||||
pstBufferCxt->dwNumOfBuffers = wNumberOfBuffers;
|
||||
if (pstBufferCxt == NULL)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Init(void) BUFCxt Init Failure\n")));
|
||||
BUF_Close();
|
||||
return BUF_CRITICAL_ERROR;
|
||||
}
|
||||
|
||||
/* Initialize buffer list */
|
||||
pstBufferCxt->pBufferList = (Buffer *)WMR_MALLOC(sizeof(Buffer) * pstBufferCxt->dwNumOfBuffers);
|
||||
|
||||
if (pstBufferCxt->pBufferList == NULL)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Init(void) BUFCxt->pBufferList Init Failure\n")));
|
||||
BUF_Close();
|
||||
return BUF_CRITICAL_ERROR;
|
||||
}
|
||||
|
||||
pBufIdx = pstBufferCxt->pBufferList;
|
||||
|
||||
for (nBufIdx = 0; nBufIdx < pstBufferCxt->dwNumOfBuffers; nBufIdx++)
|
||||
{
|
||||
#ifdef WMR_USE_FAKE_POINTERS
|
||||
/*
|
||||
* In order to make it possible to DMA to the contents of the buffer pool,
|
||||
* OAM_Init has already allocated an IOBufferMemoryDescriptor of the appropriate
|
||||
* size. Thus, we just have to index into it...
|
||||
*/
|
||||
extern UInt8 *_OAM_PageBufferPoolBase;
|
||||
extern UInt8 *_OAM_SpareBufferPoolBase;
|
||||
pBufIdx->pData = _OAM_PageBufferPoolBase + (nBufIdx * BYTES_PER_PAGE);
|
||||
pBufIdx->pSpare = _OAM_SpareBufferPoolBase + (nBufIdx * BYTES_PER_PAGE_META);
|
||||
#else /* !WMR_USE_FAKE_POINTERS */
|
||||
pBufIdx->pData = (UInt8 *)WMR_MALLOC(BYTES_PER_PAGE + BYTES_PER_PAGE_META);
|
||||
pBufIdx->pSpare = pBufIdx->pData + BYTES_PER_PAGE;
|
||||
#endif
|
||||
|
||||
if (pBufIdx->pData == NULL || pBufIdx->pSpare == NULL)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Init(void) pBufIdx->pData, pBufIdx->pSpare Init Failure\n")));
|
||||
BUF_Close();
|
||||
return BUF_CRITICAL_ERROR;
|
||||
}
|
||||
|
||||
pBufIdx->pDataBak = pBufIdx->pData;
|
||||
#ifdef WMR_USE_FAKE_POINTERS /* need to save the spare pointer as it is not contiguous */
|
||||
pBufIdx->pSpareBak = pBufIdx->pSpare;
|
||||
#endif
|
||||
pBufIdx->eStatus = BUF_FREE;
|
||||
|
||||
pBufIdx++;
|
||||
}
|
||||
|
||||
pstBufferCxt->nFreeBuffers = pstBufferCxt->dwNumOfBuffers;
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF:OUT] --BUF_Init(void) nRe=0x%x\n"), BUF_SUCCESS));
|
||||
return BUF_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* NAME */
|
||||
/* BUF_Get */
|
||||
/* DESCRIPTION */
|
||||
/* This function returns a new free buffer. */
|
||||
/* if there is not a free buffer, this function calls the sync function */
|
||||
/* and generates a new free buffer. */
|
||||
/* PARAMETERS */
|
||||
/* eType [IN] */
|
||||
/* buffer type */
|
||||
/* RETURN VALUES */
|
||||
/* Buffer */
|
||||
/* BUF_Get is completed. */
|
||||
/* NULL */
|
||||
/* BUF_Get is failed. */
|
||||
/* NOTES */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
Buffer *
|
||||
BUF_Get(BUFType eType)
|
||||
{
|
||||
UInt32 nBufIdx;
|
||||
Buffer *pBufRet;
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF: IN] ++BUF_Get(eType = %d)\n"), eType));
|
||||
|
||||
/* Check buffer context was initialized */
|
||||
if (pstBufferCxt == NULL)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Get(eType = %d) Buffer manager is not initialized\n"), eType));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* NirW - from the checked in M1 code - Check buffer context was not written over */
|
||||
if (pstBufferCxt->pBufferList == NULL)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Get(eType = %d) Buffer pointer was overwritten!\n"), eType));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pstBufferCxt->nFreeBuffers == 0)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Get(eType = %d) No free buffer\n"), eType));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find a free buffer from the buffer pool. */
|
||||
pBufRet = pstBufferCxt->pBufferList;
|
||||
|
||||
for (nBufIdx = 0; nBufIdx < pstBufferCxt->dwNumOfBuffers; nBufIdx++, pBufRet++)
|
||||
{
|
||||
if (pBufRet->eStatus == BUF_FREE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nBufIdx >= pstBufferCxt->dwNumOfBuffers)
|
||||
{
|
||||
BUF_ERR_PRINT((TEXT("[BUF:ERR] BUF_Get(eType = %d) Can't find a free buffer\n"), eType));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check the buffer type */
|
||||
if (eType == BUF_SPARE_ONLY)
|
||||
{
|
||||
pBufRet->pData = NULL;
|
||||
}
|
||||
else if (eType == BUF_MAIN_ONLY)
|
||||
{
|
||||
pBufRet->pSpare = NULL;
|
||||
}
|
||||
|
||||
/* Initialize the spare buffer */
|
||||
if (eType != BUF_MAIN_ONLY)
|
||||
{
|
||||
WMR_MEMSET(pBufRet->pSpare, 0xFF, BYTES_PER_PAGE_META);
|
||||
}
|
||||
|
||||
/* Change the buffer status & bitmap */
|
||||
pBufRet->eStatus = BUF_ALLOCATED;
|
||||
/* pBufRet->nBitmap = 0; */
|
||||
|
||||
/* Decrease the number of free buffers */
|
||||
pstBufferCxt->nFreeBuffers--;
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF:OUT] --BUF_Get(eType = %d)\n"), eType));
|
||||
|
||||
return pBufRet;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* NAME */
|
||||
/* BUF_Release */
|
||||
/* DESCRIPTION */
|
||||
/* This function releases the buffer to the buffer pool. */
|
||||
/* PARAMETERS */
|
||||
/* pBuf [IN] */
|
||||
/* buffer pointer */
|
||||
/* RETURN VALUES */
|
||||
/* none */
|
||||
/* NOTES */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
void
|
||||
BUF_Release(Buffer *pBuf)
|
||||
{
|
||||
UInt16 wIdx;
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF: IN] ++BUF_Release(pBuf = %x)\n"), pBuf));
|
||||
|
||||
if (pBuf == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//WMR_ASSERT((pBuf - pstBufferCxt->pBufferList) >= 0 &&
|
||||
// (pBuf - pstBufferCxt->pBufferList) < pstBufferCxt->dwNumOfBuffers);
|
||||
for (wIdx = 0; wIdx < pstBufferCxt->dwNumOfBuffers; wIdx++)
|
||||
{
|
||||
if (pBuf == &pstBufferCxt->pBufferList[wIdx])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
WMR_ASSERT(wIdx < pstBufferCxt->dwNumOfBuffers);
|
||||
/* NirW */
|
||||
if (pBuf->eStatus == BUF_FREE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WMR_ASSERT(pBuf->eStatus == BUF_ALLOCATED);
|
||||
|
||||
/* Reinitialize the buffer */
|
||||
pBuf->pData = pBuf->pDataBak;
|
||||
#ifdef WMR_USE_FAKE_POINTERS /* need to restore non-adjacent spare pointer */
|
||||
pBuf->pSpare = pBuf->pSpareBak;
|
||||
#else
|
||||
pBuf->pSpare = pBuf->pDataBak + BYTES_PER_PAGE;
|
||||
#endif
|
||||
|
||||
pBuf->eStatus = BUF_FREE;
|
||||
|
||||
pstBufferCxt->nFreeBuffers++;
|
||||
|
||||
WMR_ASSERT(pstBufferCxt->nFreeBuffers <= pstBufferCxt->dwNumOfBuffers);
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF:OUT] --BUF_Release(pBuf = %x)\n"), pBuf));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* NAME */
|
||||
/* BUF_Close */
|
||||
/* DESCRIPTION */
|
||||
/* This function releases buffer manager context. */
|
||||
/* PARAMETERS */
|
||||
/* none */
|
||||
/* RETURN VALUES */
|
||||
/* none */
|
||||
/* NOTES */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
void
|
||||
BUF_Close(void)
|
||||
{
|
||||
UInt32 nBufIdx;
|
||||
Buffer *pBufIdx;
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF: IN] ++BUF_Close(void)\n")));
|
||||
|
||||
if (pstBufferCxt != NULL)
|
||||
{
|
||||
if (pstBufferCxt->pBufferList != NULL)
|
||||
{
|
||||
pBufIdx = pstBufferCxt->pBufferList;
|
||||
|
||||
for (nBufIdx = 0; nBufIdx < pstBufferCxt->dwNumOfBuffers; nBufIdx++)
|
||||
{
|
||||
#ifndef WMR_USE_FAKE_POINTERS
|
||||
WMR_FREE(pBufIdx->pDataBak, (BYTES_PER_PAGE + BYTES_PER_PAGE_META));
|
||||
#endif
|
||||
pBufIdx->pData = NULL;
|
||||
pBufIdx->pSpare = NULL;
|
||||
|
||||
pBufIdx++;
|
||||
}
|
||||
|
||||
WMR_FREE(pstBufferCxt->pBufferList, (sizeof(Buffer) * pstBufferCxt->dwNumOfBuffers));
|
||||
|
||||
pstBufferCxt->pBufferList = NULL;
|
||||
}
|
||||
|
||||
WMR_FREE(pstBufferCxt, sizeof(BUFCxt));
|
||||
|
||||
pstBufferCxt = NULL;
|
||||
}
|
||||
|
||||
BUF_LOG_PRINT((TEXT("[BUF:OUT] --BUF_Close(void)\n")));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
BUF_ReleaseAllBuffers(void)
|
||||
{
|
||||
UInt32 nBufIdx;
|
||||
Buffer *pBufIdx;
|
||||
|
||||
pBufIdx = pstBufferCxt->pBufferList;
|
||||
|
||||
for (nBufIdx = 0; nBufIdx < pstBufferCxt->dwNumOfBuffers; nBufIdx++)
|
||||
{
|
||||
BUF_Release(pBufIdx);
|
||||
pBufIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* COMPONENT : Rainbow */
|
||||
/* MODULE : Virtual Flash Layer */
|
||||
/* NAME : VFL Buffer Management */
|
||||
/* FILE : VFLBuffer.h */
|
||||
/* PURPOSE : This file contains routines for managing buffers which */
|
||||
/* whimory uses. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* COPYRIGHT 2003-2005 SAMSUNG ELECTRONICS CO., LTD. */
|
||||
/* ALL RIGHTS RESERVED */
|
||||
/* */
|
||||
/* Permission is hereby granted to licensees of Samsung Electronics */
|
||||
/* Co., Ltd. products to use or abstract this computer program for the */
|
||||
/* sole purpose of implementing a product based on Samsung */
|
||||
/* Electronics Co., Ltd. products. No other rights to reproduce, use, */
|
||||
/* or disseminate this computer program, whether in part or in whole, */
|
||||
/* are granted. */
|
||||
/* */
|
||||
/* Samsung Electronics Co., Ltd. makes no representation or warranties */
|
||||
/* with respect to the performance of this computer program, and */
|
||||
/* specifically disclaims any responsibility for any damages, */
|
||||
/* special or consequential, connected with the use of this program. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* REVISION HISTORY */
|
||||
/* */
|
||||
/* 13-JUL-2005 [Jaesung Jung] : separate from vfl.c & reorganize code */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef _VFL_BUFFER_H_
|
||||
#define _VFL_BUFFER_H_
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Return value of BUF_XXX() */
|
||||
/*****************************************************************************/
|
||||
#define BUF_SUCCESS ANDErrorCodeOk
|
||||
#define BUF_CRITICAL_ERROR ANDErrorCodeAllocFailErr
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Buffer state enum definition */
|
||||
/*****************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
BUF_FREE = 0x10000000, /* the buffer is free */
|
||||
BUF_ALLOCATED = 0x10000001, /* the buffer is allocated to some layer */
|
||||
} BUFStat;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Buffer type enum & macro definition */
|
||||
/*****************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
BUF_MAIN_AND_SPARE = 0x10000000, /* to get a buffer which has main & spare*/
|
||||
BUF_MAIN_ONLY = 0x10000001, /* to get a buffer which has main only */
|
||||
BUF_SPARE_ONLY = 0x10000002 /* to get a buffer which has spare only */
|
||||
} BUFType;
|
||||
|
||||
#define BITMAP_FULL_PAGE ((1 << SECTORS_PER_PAGE) - 1)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Buffer structure definition */
|
||||
/*****************************************************************************/
|
||||
typedef struct Buf
|
||||
{
|
||||
UInt8 *pData; /* buffer area for main area */
|
||||
UInt8 *pSpare; /* buffer area for spare area */
|
||||
// UInt32 nBitmap; /* valid sector bitmap for pData */
|
||||
BUFStat eStatus; /* the status of buffer */
|
||||
UInt8 *pDataBak; /* the original pointer of data buffer */
|
||||
#ifdef WMR_USE_FAKE_POINTERS /* data and spare buffers are not adjacent */
|
||||
UInt8 *pSpareBak; /* the original pointer of spare buffer */
|
||||
#endif
|
||||
} Buffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Buffer *pBufferList; /* the list of all the buffers */
|
||||
UInt32 nFreeBuffers; /* the count of free buffers */
|
||||
UInt32 dwNumOfBuffers;
|
||||
} BUFCxt;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* exported function prototype of VFL buffer manager */
|
||||
/*****************************************************************************/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
Int32 BUF_Init(UInt16 wDataBytesPerPage, UInt16 wMetaBytesPerPage, UInt16 wNumberOfBuffers);
|
||||
Buffer *BUF_Get(BUFType eType);
|
||||
void BUF_Release(Buffer *pBuf);
|
||||
void BUF_Close(void);
|
||||
void BUF_ReleaseAllBuffers(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _VFL_BUFFER_H_ */
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_H__
|
||||
#define __L2V_H__
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern L2V_t L2V;
|
||||
extern UInt32 L2V_nodepool_mem;
|
||||
extern UInt8 *L2V_root_depth;
|
||||
extern tempNodePool_t tempNodes;
|
||||
|
||||
#endif // __L2V_H__
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_CASSERT_H__
|
||||
#define __L2V_CASSERT_H__
|
||||
|
||||
#define l2v_assert(e) WMR_ASSERT(e)
|
||||
|
||||
#define l2v_assert_le(x, y) l2v_assert((x) <= (y))
|
||||
#define l2v_assert_lt(x, y) l2v_assert((x) < (y))
|
||||
#define l2v_assert_ge(x, y) l2v_assert((x) >= (y))
|
||||
#define l2v_assert_gt(x, y) l2v_assert((x) > (y))
|
||||
#define l2v_assert_eq(x, y) l2v_assert((x) == (y))
|
||||
#define l2v_assert_ne(x, y) l2v_assert((x) != (y))
|
||||
|
||||
#endif // __L2V_CASSERT_H__
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_CONFIG_H__
|
||||
#define __L2V_CONFIG_H__
|
||||
|
||||
// Defines the node size
|
||||
#define L2V_NODE_SIZE 64
|
||||
|
||||
// Defines the memory set aside for the node pool
|
||||
#define L2V_NODEPOOL_MEM (L2V_nodepool_mem + 0)
|
||||
// Defines the size of a logical tree
|
||||
#define L2V_TREE_BITS 15
|
||||
|
||||
// Repack periodicity
|
||||
#define L2V_REPACK_PERIOD 200
|
||||
|
||||
|
||||
#endif // __L2V_CONFIG_H__
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_DEFINES_H__
|
||||
#define __L2V_DEFINES_H__
|
||||
|
||||
// Shortcuts for the config
|
||||
#define b_1 0
|
||||
#define b_2 1
|
||||
#define b_4 2
|
||||
#define b_8 3
|
||||
#define b_16 4
|
||||
#define b_32 5
|
||||
#define b_64 6
|
||||
#define b_128 7
|
||||
#define b_256 8
|
||||
#define b_512 9
|
||||
#define KiB_bits 10
|
||||
#define MiB_bits 20
|
||||
#define GiB_bits 30
|
||||
#define TiB_bits 40
|
||||
#define KiB (1 << KiB_bits)
|
||||
#define MiB (1 << MiB_bits)
|
||||
#define GiB (1 << GiB_bits)
|
||||
#define TiB (1 << TiB_bits)
|
||||
|
||||
#include "L2V_Config.h"
|
||||
|
||||
|
||||
// Node size
|
||||
#define L2V_CONTIG_ELEM_SMALL 4
|
||||
#define L2V_CONTIG_ELEM_LARGE 6
|
||||
#define L2V_MIN_CONTIG_PER_NODE (L2V_NODE_SIZE / L2V_CONTIG_ELEM_LARGE)
|
||||
#define L2V_MAX_CONTIG_PER_NODE (L2V_NODE_SIZE / L2V_CONTIG_ELEM_SMALL)
|
||||
|
||||
|
||||
// Memory usage
|
||||
#define L2V_NODEPOOL_COUNT (L2V_NODEPOOL_MEM / L2V_NODE_SIZE)
|
||||
|
||||
|
||||
// Parameters
|
||||
#define L2V_SUCKUP_CHILDREN_MAX 3
|
||||
#define L2V_TRACK_VALID 1
|
||||
|
||||
|
||||
// Tree size
|
||||
#define L2V_TREE_SIZE (1 << L2V_TREE_BITS)
|
||||
#define L2V_TREE_MASK (L2V_TREE_SIZE - 1)
|
||||
#define L2V_MAX_TREE_DEPTH 32
|
||||
#define L2V_MAX_TREE_DEPTH_UPD 36
|
||||
#define L2V_TREE_DEPTH_REPACK 26
|
||||
|
||||
|
||||
// Magic numbers
|
||||
#define L2V_CONTIG_FREE_SIG 0xFFFFFFFF
|
||||
// VBA macros, to make quick read-only accessors
|
||||
#define L2V_VBA_SPECIAL (L2V.vba.special+0)
|
||||
#define L2V_VBA_DEALLOC (L2V.vba.dealloc+0)
|
||||
|
||||
|
||||
// Transforms
|
||||
#define L2V_IDX_TO_NODE(idx) (&L2V.Pool.Node[idx])
|
||||
#define L2V_NODE_TO_IDX(ptr) ((lNode_t*)(ptr) - &L2V.Pool.Node[0])
|
||||
|
||||
// Memory state
|
||||
#define L2V_LowishMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*16))
|
||||
#define L2V_LowMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*8))
|
||||
#define L2V_CriticalMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH+1))
|
||||
#define L2V_TimeToRepack (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH << 1))
|
||||
|
||||
// Frag search
|
||||
#define L2V_FIND_FRAGS_MAX 32
|
||||
#define L2V_LIST_FRAGS_MAX 64
|
||||
|
||||
|
||||
#endif // __L2V_DEFINES_H__
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
//
|
||||
// L2V_Dump.m
|
||||
// L2V_Dump
|
||||
//
|
||||
// Created by John Vink on 7/29/11.
|
||||
// Copyright (c) 2011 Apple, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import "L2V_Print.h"
|
||||
#import "L2V_Types.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define L2V_SIZE_32_BIT (0x3c)
|
||||
#define L2V_SIZE_64_BIT (0x50)
|
||||
#define L2V_OFFSET_POOL_64_BIT (0x38)
|
||||
#define SIZE_OF_LONG_64_BIT 8
|
||||
|
||||
L2V_t L2V;
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// * usage
|
||||
// -------------------------------------------------------------
|
||||
static void usage()
|
||||
{
|
||||
printf("L2V_Dump: <file>\n");
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// * main
|
||||
// -------------------------------------------------------------
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
NSAutoreleasePool* pool = [NSAutoreleasePool new];
|
||||
|
||||
// try to make sure the L2V struct hasn't changed (much) since I wrote the code to convert it from 32 bit to 64 bit
|
||||
if (sizeof(long) == SIZE_OF_LONG_64_BIT)
|
||||
{
|
||||
L2V_t* dummyL2V = (L2V_t*) 0;
|
||||
if (sizeof(L2V_t) != L2V_SIZE_64_BIT || (long)&dummyL2V->Pool != L2V_OFFSET_POOL_64_BIT)
|
||||
{
|
||||
printf("L2V struct has changed.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "architecture: %d bit\n", sizeof(long) * 8);
|
||||
|
||||
L2V_t* dummyL2V = (L2V_t*) 0;
|
||||
printf("numRoots %2x %d\n", &dummyL2V->numRoots, sizeof(dummyL2V->numRoots));
|
||||
printf("Root %2x %d\n", &dummyL2V->Root, sizeof(dummyL2V->Root));
|
||||
printf("RepackCounter %2x %d\n", &dummyL2V->RepackCounter, sizeof(dummyL2V->RepackCounter));
|
||||
printf("treeVersion %2x %d\n", &dummyL2V->treeVersion, sizeof(dummyL2V->treeVersion));
|
||||
printf("max_sb %2x %d\n", &dummyL2V->max_sb, sizeof(dummyL2V->max_sb));
|
||||
printf("vbas_per_sb %2x %d\n", &dummyL2V->vbas_per_sb, sizeof(dummyL2V->vbas_per_sb));
|
||||
printf("bits %2x %d\n", &dummyL2V->bits, sizeof(dummyL2V->bits));
|
||||
printf("bits.node_span %2x %d\n", &dummyL2V->bits.node_span, sizeof(dummyL2V->bits.node_span));
|
||||
printf("bits.nodeIdx %2x %d\n", &dummyL2V->bits.nodeIdx, sizeof(dummyL2V->bits.nodeIdx));
|
||||
printf("bits.nand_span %2x %d\n", &dummyL2V->bits.nand_span, sizeof(dummyL2V->bits.nand_span));
|
||||
printf("bits.vba %2x %d\n", &dummyL2V->bits.vba, sizeof(dummyL2V->bits.vba));
|
||||
printf("vba %2x %d\n", &dummyL2V->vba, sizeof(dummyL2V->vba));
|
||||
printf("vba.special %2x %d\n", &dummyL2V->vba.special, sizeof(dummyL2V->vba.special));
|
||||
printf("vba.dealloc %2x %d\n", &dummyL2V->vba.dealloc, sizeof(dummyL2V->vba.dealloc));
|
||||
printf("Pool %2x %d\n", &dummyL2V->Pool, sizeof(dummyL2V->Pool));
|
||||
printf("Total Size %2x\n", sizeof(L2V_t));
|
||||
#endif
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* filename = argv[1];
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (-1 == fd)
|
||||
{
|
||||
fprintf(stderr, "Cannot open %s\n", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// see how big the XML is
|
||||
UInt32 xmlSize = 0;
|
||||
ssize_t result = read(fd, &xmlSize, sizeof(xmlSize));
|
||||
if (sizeof(xmlSize) != result)
|
||||
{
|
||||
fprintf(stderr, "Unable to read size of XML\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read the XML
|
||||
char* xmlBuffer = (char*) malloc(xmlSize);
|
||||
if (NULL == xmlBuffer)
|
||||
{
|
||||
fprintf(stderr, "Cannot allocate XML buffer of %d\n", xmlSize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
result = read(fd, xmlBuffer, xmlSize);
|
||||
if ((ssize_t)xmlSize != result)
|
||||
{
|
||||
fprintf(stderr, "Unable to read XML\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSData* xmlData = [NSData dataWithBytes:xmlBuffer length:xmlSize];
|
||||
if (NULL == xmlData)
|
||||
{
|
||||
fprintf(stderr, "Cannot create NSData from XML buffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSPropertyListReadOptions format = NSPropertyListXMLFormat_v1_0;
|
||||
NSError* error = NULL;
|
||||
NSDictionary* dict = [NSPropertyListSerialization propertyListWithData:xmlData options:0 format:&format error:&error];
|
||||
if (NULL == dict)
|
||||
{
|
||||
fprintf(stderr, "Cannot convert XML data to NSDictionary\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSDictionary* infoDict = [dict objectForKey:@"Info"];
|
||||
if (NULL == infoDict || ![infoDict isKindOfClass:[NSDictionary class]])
|
||||
{
|
||||
fprintf(stderr, "Cannot get Info dict\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSNumber* ftlTypeNumber = [infoDict objectForKey:@"FTL Type"];
|
||||
if (NULL == ftlTypeNumber || ![ftlTypeNumber isKindOfClass:[NSNumber class]])
|
||||
{
|
||||
fprintf(stderr, "Cannot get FTL Type from Info dict\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ([ftlTypeNumber intValue] != FTL_TYPE_SFTL)
|
||||
{
|
||||
fprintf(stderr, "FTL type is not AppleSwiss\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSArray* blobs = [dict objectForKey:@"Blobs"];
|
||||
if (NULL == blobs || ![blobs isKindOfClass:[NSArray class]])
|
||||
{
|
||||
fprintf(stderr, "Cannot get Blobs array\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSDictionary* structDict;
|
||||
L2V_t l2vStruct;
|
||||
for (structDict in blobs)
|
||||
{
|
||||
if (![structDict isKindOfClass:[NSDictionary class]])
|
||||
{
|
||||
fprintf(stderr, "Blobs element is not a dictionary\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSString* structType = [structDict objectForKey:@"Label"];
|
||||
NSNumber* structSize = [structDict objectForKey:@"Size"];
|
||||
|
||||
if (NULL == structType || ![structType isKindOfClass:[NSString class]])
|
||||
{
|
||||
fprintf(stderr, "Cannot get Blob label\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NULL == structSize || ![structSize isKindOfClass:[NSNumber class]])
|
||||
{
|
||||
fprintf(stderr, "Cannot get Blob size\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ([structType isEqualToString:@"AND_STRUCT_FTL_L2V_STRUCT"])
|
||||
{
|
||||
BOOL read32Bit = NO;
|
||||
if ([structSize intValue] != sizeof(L2V_t))
|
||||
{
|
||||
if ([structSize intValue] == L2V_SIZE_32_BIT)
|
||||
{
|
||||
read32Bit = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Expected size of %d for L2V, but got %d\n", sizeof(L2V_t), [structSize intValue]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (read32Bit)
|
||||
{
|
||||
uint8_t* l2v32bitBuffer = malloc(L2V_SIZE_32_BIT);
|
||||
result = read(fd, l2v32bitBuffer, L2V_SIZE_32_BIT);
|
||||
if (result != L2V_SIZE_32_BIT)
|
||||
{
|
||||
fprintf(stderr, "Could not read L2V struct\n");
|
||||
free(l2v32bitBuffer);
|
||||
return 1;
|
||||
}
|
||||
l2vStruct.numRoots = *(UInt32*)l2v32bitBuffer;
|
||||
l2vStruct.RepackCounter = *(UInt32*)&l2v32bitBuffer[8];
|
||||
l2vStruct.treeVersion = *(UInt32*)&l2v32bitBuffer[0xc];
|
||||
l2vStruct.max_sb = *(UInt32*)&l2v32bitBuffer[0x10];
|
||||
l2vStruct.vbas_per_sb = *(UInt32*)&l2v32bitBuffer[0x14];
|
||||
l2vStruct.bits.node_span = *(UInt32*)&l2v32bitBuffer[0x18];
|
||||
l2vStruct.bits.nodeIdx = *(UInt32*)&l2v32bitBuffer[0x1c];
|
||||
l2vStruct.bits.nand_span = *(UInt32*)&l2v32bitBuffer[0x20];
|
||||
l2vStruct.bits.vba = *(UInt32*)&l2v32bitBuffer[0x24];
|
||||
l2vStruct.vba.special = *(UInt32*)&l2v32bitBuffer[0x28];
|
||||
l2vStruct.vba.dealloc = *(UInt32*)&l2v32bitBuffer[0x2c];
|
||||
free(l2v32bitBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = read(fd, &l2vStruct, sizeof(L2V_t));
|
||||
if (result != sizeof(L2V_t))
|
||||
{
|
||||
fprintf(stderr, "Could not read L2V struct\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([structType isEqualToString:@"AND_STRUCT_FTL_L2V_ROOTS"])
|
||||
{
|
||||
UInt32 rootSize = [structSize intValue];
|
||||
l2vStruct.Root = malloc(rootSize);
|
||||
if (NULL == l2vStruct.Root)
|
||||
{
|
||||
fprintf(stderr, "Could not allocate %d bytes for roots\n", rootSize);
|
||||
return 1;
|
||||
}
|
||||
result = read(fd, l2vStruct.Root, rootSize);
|
||||
if (result != (ssize_t)rootSize)
|
||||
{
|
||||
fprintf(stderr, "Could not read L2V roots\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ([structType isEqualToString:@"AND_STRUCT_FTL_L2V_POOL"])
|
||||
{
|
||||
UInt32 poolSize = [structSize intValue];
|
||||
l2vStruct.Pool.Node = malloc(poolSize);
|
||||
if (NULL == l2vStruct.Pool.Node)
|
||||
{
|
||||
fprintf(stderr, "Could not allocate %d bytes for pool\n", poolSize);
|
||||
return 1;
|
||||
}
|
||||
result = read(fd, l2vStruct.Pool.Node, poolSize);
|
||||
if (result != (ssize_t)poolSize)
|
||||
{
|
||||
fprintf(stderr, "Could not read L2V pool\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown label %s\n", [structType cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
l2vStruct.Pool.FreePtr = NULL;
|
||||
l2vStruct.Pool.FreeCount = 0;
|
||||
|
||||
L2V = l2vStruct;
|
||||
|
||||
printf("Number of roots:%d\n", l2vStruct.numRoots);
|
||||
UInt32 rootNumber;
|
||||
for (rootNumber = 0; rootNumber < l2vStruct.numRoots; rootNumber++)
|
||||
{
|
||||
printf("---- Root %d:\n", rootNumber);
|
||||
L2V_PrintUsage(rootNumber);
|
||||
}
|
||||
|
||||
[pool release];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// L2V_Dump_Prefix.h
|
||||
// IOFlashStorage
|
||||
//
|
||||
// Created by John Vink on 7/29/11.
|
||||
// Copyright (c) 2011 Apple, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
// include these files so that L2V_Print.c will build
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define _WMR_ASSERT(e, file, line) { printf("%s:%u: failed assertion '%s'\nWaiting for debugger...\n", file, line, e); abort(); }
|
||||
#define WMR_ASSERT(e) if (!(e)) _WMR_ASSERT(#e, __FILE__, __LINE__)
|
||||
#define WMR_PANIC(fmt, ...) { printf(fmt, ## __VA_ARGS__); abort(); }
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_EXTERN_H__
|
||||
#define __L2V_EXTERN_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
// Define the context structure for faster macro access
|
||||
extern L2V_t L2V;
|
||||
extern UInt32 L2V_nodepool_mem;
|
||||
extern UInt8 *L2V_root_depth;
|
||||
extern tempNodePool_t tempNodes;
|
||||
|
||||
extern BOOL32 L2V_Init(UInt32 numLbas, UInt32 max_sb, UInt32 vbas_per_sb);
|
||||
extern void L2V_Nuke(void);
|
||||
extern void L2V_Free(void);
|
||||
extern void L2V_Search_Init(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Search(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Update(UInt32 lba, UInt32 size, UInt32 vba);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
extern UInt32 L2V_ForceRepack(void);
|
||||
extern void L2V_FindFrag(UInt32 *d_lba, UInt32 *d_span);
|
||||
|
||||
#define L2V_IdleRepackThr (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*32))
|
||||
#define L2V_LowishMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*16))
|
||||
#define L2V_LowMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*8))
|
||||
#define L2V_CriticalMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH+1))
|
||||
|
||||
|
||||
#endif // __L2V_EXTERN_H__
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2009-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 "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
typedef struct {
|
||||
UInt32 lba;
|
||||
UInt32 span;
|
||||
} fragItem_t;
|
||||
|
||||
static struct {
|
||||
UInt32 curLba;
|
||||
fragItem_t item[L2V_FIND_FRAGS_MAX];
|
||||
UInt32 nextIdx;
|
||||
UInt32 idx;
|
||||
UInt32 cnt;
|
||||
UInt32 sum;
|
||||
UInt32 minSum;
|
||||
UInt32 minSumLba;
|
||||
|
||||
fragItem_t listItem[L2V_LIST_FRAGS_MAX+1];
|
||||
UInt32 listSize;
|
||||
|
||||
Int32 curTree;
|
||||
} frag;
|
||||
|
||||
static void TreeFrag(lNode_t *node);
|
||||
|
||||
void L2V_FindFrag(UInt32 *d_lba, UInt32 *d_span)
|
||||
{
|
||||
lNode_t *root;
|
||||
UInt32 tree;
|
||||
UInt32 lba, span;
|
||||
UInt32 curIdx;
|
||||
RootContig_t rc;
|
||||
|
||||
if (frag.listSize < (L2V_LIST_FRAGS_MAX>>2)) {
|
||||
// Initialize structures
|
||||
frag.idx = 0;
|
||||
frag.cnt = 0;
|
||||
frag.sum = 0;
|
||||
frag.minSum = 0xffffffff;
|
||||
frag.minSumLba = 0xffffffff;
|
||||
|
||||
// Iterate over roots
|
||||
for (tree = 0; tree < L2V.numRoots; tree++, frag.curTree--) {
|
||||
if (frag.curTree < 0) {
|
||||
frag.curTree = L2V.numRoots-1;
|
||||
}
|
||||
frag.curLba = frag.curTree << L2V_TREE_BITS;
|
||||
|
||||
rc = L2V.Root[frag.curTree].rootContig;
|
||||
|
||||
// No fragments if there's no tree!
|
||||
if (ROOT_CONTIG_DEALLOC == rc) {
|
||||
frag.curLba += L2V_TREE_SIZE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Recurse and destroy
|
||||
root = L2V_IDX_TO_NODE(ROOT_CONTIG_GET_NODEIDX(rc));
|
||||
TreeFrag(root);
|
||||
|
||||
if (frag.listSize && (L2V_FIND_FRAGS_MAX == frag.listItem[0].span)) {
|
||||
// Early out: it can't get any smaller!
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract from queue
|
||||
lba = frag.listItem[0].lba;
|
||||
span = frag.listItem[0].span;
|
||||
for (curIdx = 1; curIdx < frag.listSize; curIdx++) {
|
||||
frag.listItem[curIdx-1] = frag.listItem[curIdx];
|
||||
}
|
||||
frag.listSize--;
|
||||
|
||||
// Limit
|
||||
span = WMR_MIN(span, L2V.vbas_per_sb<<1);
|
||||
|
||||
// Report it
|
||||
*d_lba = lba;
|
||||
*d_span = span;
|
||||
}
|
||||
|
||||
static void TreeFrag(lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
UInt32 curIdx;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
// Recurse
|
||||
TreeFrag(L2V_IDX_TO_NODE(cu.u.nodeIdx));
|
||||
} else {
|
||||
// Prepare next index
|
||||
frag.nextIdx = frag.idx + 1;
|
||||
if (frag.nextIdx >= L2V_FIND_FRAGS_MAX)
|
||||
frag.nextIdx = 0;
|
||||
|
||||
// Subtract prior span if the search is full
|
||||
if (L2V_FIND_FRAGS_MAX == frag.cnt) {
|
||||
frag.sum -= frag.item[frag.idx].span;
|
||||
}
|
||||
|
||||
// Add to rolling average
|
||||
frag.item[frag.idx].span = cu.span;
|
||||
frag.item[frag.idx].lba = frag.curLba;
|
||||
frag.sum += cu.span;
|
||||
frag.cnt = WMR_MIN(frag.cnt+1, L2V_FIND_FRAGS_MAX);
|
||||
|
||||
// Minify
|
||||
if (L2V_FIND_FRAGS_MAX == frag.cnt) {
|
||||
if (frag.listSize < L2V_LIST_FRAGS_MAX) {
|
||||
frag.listItem[frag.listSize].lba = (UInt32)-1;
|
||||
frag.listItem[frag.listSize].span = (UInt32)-1;
|
||||
frag.listSize++;
|
||||
}
|
||||
|
||||
// Insert, slipping from end
|
||||
curIdx = frag.listSize;
|
||||
while ((curIdx > 0) && (frag.sum < frag.listItem[curIdx-1].span)) {
|
||||
curIdx--;
|
||||
frag.listItem[curIdx+1].lba = frag.listItem[curIdx].lba;
|
||||
frag.listItem[curIdx+1].span = frag.listItem[curIdx].span;
|
||||
}
|
||||
|
||||
if (curIdx < frag.listSize) {
|
||||
frag.listItem[curIdx].lba = frag.item[frag.nextIdx].lba;
|
||||
frag.listItem[curIdx].span = frag.sum;
|
||||
// Empty pending, to guarantee no overlaps
|
||||
frag.idx = 0;
|
||||
frag.sum = 0;
|
||||
frag.cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Next
|
||||
frag.curLba += cu.span;
|
||||
frag.idx = frag.nextIdx;
|
||||
}
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 "L2V_Extern.h"
|
||||
|
||||
void L2V_Free(void)
|
||||
{
|
||||
if (0 == L2V.numRoots)
|
||||
return;
|
||||
|
||||
// Free arrays:
|
||||
|
||||
if (NULL != L2V.Root) {
|
||||
WMR_FREE(L2V.Root, L2V.numRoots * sizeof(Root_t));
|
||||
L2V.Root = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.Pool.Node) {
|
||||
WMR_FREE(L2V.Pool.Node, L2V_NODEPOOL_MEM);
|
||||
L2V.Pool.Node = NULL;
|
||||
}
|
||||
|
||||
if(L2V_root_depth != NULL)
|
||||
{
|
||||
WMR_FREE(L2V_root_depth, L2V.numRoots);
|
||||
L2V_root_depth = NULL;
|
||||
}
|
||||
|
||||
if(tempNodes.isEntryAvailable)
|
||||
{
|
||||
WMR_FREE(tempNodes.isEntryAvailable, tempNodes.poolSize);
|
||||
}
|
||||
if(tempNodes.tempNodeEntries)
|
||||
{
|
||||
WMR_FREE(tempNodes.tempNodeEntries, sizeof(lNodeBig_t) * tempNodes.poolSize);
|
||||
}
|
||||
tempNodes.poolSize = 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V_Funcs.h"
|
||||
|
||||
// Empty
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_FUNCS_H__
|
||||
#define __L2V_FUNCS_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern BOOL32 L2V_Init(UInt32 numLbas, UInt32 max_sb, UInt32 vbas_per_sb);
|
||||
extern void L2V_Nuke(void);
|
||||
extern void L2V_Search_Init(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Search(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Update(UInt32 lba, UInt32 size, UInt32 vba);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
|
||||
|
||||
// Macros
|
||||
|
||||
#define _L2V_NODE_ITERATE_RESUME(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr) \
|
||||
while ((_nodeByteOfs) <= ((_nodeSize)-sizeof(lPtr_t))) { \
|
||||
(_destPtr) = *(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]); \
|
||||
if (L2V_CONTIG_FREE_SIG == (_destPtr)) { \
|
||||
break; \
|
||||
} \
|
||||
if (LPTR_IS_NODEPTR(_destPtr)) { \
|
||||
LPTR_UNPACK_NODE(_destPtr, _cu); \
|
||||
} else { \
|
||||
LPTR_UNPACK_NAND(_destPtr, _cu); \
|
||||
} \
|
||||
if ((_cu).hasSpanOF) { \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
(_cu).span += *(UInt16*)&(_node)->bytes[_nodeSize] << (LPTR_IS_NODEPTR(_destPtr) ? L2V.bits.node_span : L2V.bits.nand_span); \
|
||||
l2v_assert_le(_nodeByteOfs, ((_nodeSize)-sizeof(lPtr_t))); \
|
||||
} \
|
||||
(_cu).span += 1; \
|
||||
l2v_assert_ne((_cu).span, 0);
|
||||
|
||||
#define _L2V_NODE_ITERATE(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr) \
|
||||
(_nodeByteOfs) = 0; \
|
||||
(_nodeSize) = L2V_NODE_SIZE; \
|
||||
_L2V_NODE_ITERATE_RESUME(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr)
|
||||
|
||||
|
||||
#define _L2V_NODE_ITERATE_NEXT(_nodeByteOfs) \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t);
|
||||
|
||||
#define _L2V_NODE_ITERATE_END_NOP }
|
||||
|
||||
#define _L2V_NODE_ITERATE_END(_nodeByteOfs) \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
}
|
||||
|
||||
#define _L2V_NODE_PUSH_CONTIG_NODE(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
{ \
|
||||
l2v_assert_ne((_cu).span, 0); \
|
||||
(_cu).hasSpanOF = 1; \
|
||||
*(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]) = LPTR_PACK_NODE(_cu); \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
*(UInt16*)&(_node)->bytes[_nodeSize] = ((_cu).span-1) >> L2V.bits.node_span; \
|
||||
}
|
||||
#define _L2V_NODE_PUSH_CONTIG_NAND(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
{ \
|
||||
l2v_assert_ne((_cu).span, 0); \
|
||||
(_cu).hasSpanOF = 0; \
|
||||
if ((_cu).span > (1UL << L2V.bits.nand_span)) { \
|
||||
(_cu).hasSpanOF = 1; \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
*(UInt16*)&(_node)->bytes[_nodeSize] = ((_cu).span-1) >> L2V.bits.nand_span; \
|
||||
} \
|
||||
*(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]) = LPTR_PACK_NAND(_cu); \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
}
|
||||
#define _L2V_NODE_PUSH_CONTIG(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
do { \
|
||||
if ((_cu).isNodePtr) { \
|
||||
_L2V_NODE_PUSH_CONTIG_NODE(_node, _nodeByteOfs, _nodeSize, _cu); \
|
||||
} else { \
|
||||
_L2V_NODE_PUSH_CONTIG_NAND(_node, _nodeByteOfs, _nodeSize, _cu); \
|
||||
} \
|
||||
} while (0)
|
||||
#define _L2V_CONTIG_SIZE(_cu) (sizeof(lPtr_t) + (((_cu).isNodePtr || ((_cu).span > (1UL << L2V.bits.nand_span))) ? sizeof(UInt16) : 0))
|
||||
|
||||
#define _L2V_NODE_FILL(_node, _nodeByteOfs, _nodeSize) \
|
||||
do { \
|
||||
WMR_MEMSET(&(_node)->bytes[_nodeByteOfs], 0xFF, (_nodeSize) - (_nodeByteOfs)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __L2V_FUNCS_H__
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V_Mem.h"
|
||||
|
||||
// Declare our L2V context structure here
|
||||
L2V_t L2V;
|
||||
UInt32 L2V_nodepool_mem = 0xffffffff;
|
||||
UInt8 *L2V_root_depth;
|
||||
tempNodePool_t tempNodes;
|
||||
|
||||
void L2V_Nuke(void)
|
||||
{
|
||||
UInt32 i;
|
||||
Int32 j;
|
||||
|
||||
// Set tree version
|
||||
L2V.treeVersion = 0;
|
||||
|
||||
// Empty roots; default to miss
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
L2V.Root[i].rootContig = ROOT_CONTIG_DEALLOC;
|
||||
L2V_root_depth[i] = 0;
|
||||
}
|
||||
|
||||
// Reset periodic repacker variables
|
||||
L2V.RepackCounter = 0;
|
||||
|
||||
// Finally, put all nodes in the free pool
|
||||
L2V.Pool.FreePtr = NULL;
|
||||
L2V.Pool.FreeCount = 0;
|
||||
for (j = L2V_NODEPOOL_COUNT-1; j >= 0; j--) {
|
||||
_L2V_FreeNode(&L2V.Pool.Node[j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions
|
||||
BOOL32 L2V_Init(UInt32 numLbas, UInt32 max_sb, UInt32 vbas_per_sb)
|
||||
{
|
||||
// Set up bits
|
||||
// ... nand lptrs
|
||||
L2V.bits.vba = WMR_LOG2((2 * max_sb * vbas_per_sb) - 1);
|
||||
WMR_ASSERT(L2V.bits.vba <= 30);
|
||||
L2V.bits.nand_span = 32 - 2 - L2V.bits.vba;
|
||||
|
||||
// ... node lptrs
|
||||
L2V.bits.nodeIdx = WMR_LOG2((2 * L2V_NODEPOOL_COUNT) - 1);
|
||||
WMR_ASSERT(L2V.bits.nodeIdx <= 30);
|
||||
L2V.bits.node_span = 32 - 2 - L2V.bits.nodeIdx;
|
||||
|
||||
// Set up special vbas
|
||||
L2V.vba.dealloc = (1 << L2V.bits.vba) - 1;
|
||||
L2V.vba.special = L2V.vba.dealloc;
|
||||
|
||||
// Set number of superblocks for valid accounting division
|
||||
L2V.max_sb = max_sb;
|
||||
L2V.vbas_per_sb = vbas_per_sb;
|
||||
if ((max_sb * vbas_per_sb) > (L2V.vba.special+1)) {
|
||||
WMR_PANIC("Tree bitspace not sufficient for geometry %dx%d: please re-adjust", max_sb, vbas_per_sb);
|
||||
}
|
||||
|
||||
// Calculate roots
|
||||
L2V.numRoots = (numLbas >> L2V_TREE_BITS) + 1;
|
||||
|
||||
// Allocate arrays
|
||||
L2V.Root = WMR_MALLOC(L2V.numRoots * sizeof(Root_t));
|
||||
l2v_assert_ne(L2V.Root , NULL);
|
||||
L2V_root_depth = WMR_MALLOC(L2V.numRoots);
|
||||
l2v_assert_ne(L2V_root_depth , NULL);
|
||||
|
||||
tempNodes.tempNodeEntries = NULL;
|
||||
tempNodes.isEntryAvailable = NULL;
|
||||
tempNodes.tempNodeEntries = WMR_MALLOC(sizeof(lNodeBig_t) * L2V_MAX_TREE_DEPTH);
|
||||
l2v_assert_ne(tempNodes.tempNodeEntries, NULL);
|
||||
tempNodes.isEntryAvailable = WMR_MALLOC(L2V_MAX_TREE_DEPTH);
|
||||
l2v_assert_ne(tempNodes.isEntryAvailable, NULL);
|
||||
tempNodes.poolSize = L2V_MAX_TREE_DEPTH;
|
||||
WMR_MEMSET(tempNodes.isEntryAvailable, 0xff, tempNodes.poolSize);
|
||||
|
||||
if(L2V_nodepool_mem != 0xffffffff)
|
||||
{
|
||||
L2V.Pool.Node = (lNode_t*)WMR_MALLOC(L2V_nodepool_mem);
|
||||
if (NULL == L2V.Pool.Node) {
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
L2V_Nuke();
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
|
||||
void _L2V_FreeNode(lNode_t *node)
|
||||
{
|
||||
static int freeCount = 0;
|
||||
|
||||
freeCount++;
|
||||
|
||||
l2v_assert_ge(node, &L2V.Pool.Node[0]);
|
||||
l2v_assert_le(node, &L2V.Pool.Node[L2V_NODEPOOL_COUNT]);
|
||||
|
||||
node->nextFreePtr = L2V.Pool.FreePtr;
|
||||
L2V.Pool.FreePtr = node;
|
||||
L2V.Pool.FreeCount++;
|
||||
}
|
||||
|
||||
|
||||
lNode_t *_L2V_AllocNode()
|
||||
{
|
||||
lNode_t *ret;
|
||||
static int allocCount = 0;
|
||||
|
||||
allocCount++;
|
||||
|
||||
ret = (lNode_t*)L2V.Pool.FreePtr;
|
||||
if (NULL != ret) {
|
||||
L2V.Pool.FreePtr = L2V.Pool.FreePtr->nextFreePtr;
|
||||
L2V.Pool.FreeCount--;
|
||||
_L2V_NODE_FILL(ret, 0, L2V_NODE_SIZE);
|
||||
}
|
||||
l2v_assert_ne(ret, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_MEM_H__
|
||||
#define __L2V_MEM_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void _L2V_FreeNode(lNode_t *node);
|
||||
extern lNode_t *_L2V_AllocNode(void); // Warning: may return NULL; up to caller to handle gracefully
|
||||
|
||||
|
||||
#endif // __L2V_MEM_H__
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V_Print.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V.h"
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
#define PRINT_MAXPATH 0
|
||||
|
||||
|
||||
// Prototypes
|
||||
|
||||
static int L2V_GetUsage(lNode_t *node, UInt32 *used, UInt32 *total, UInt32 *nodes, UInt32 totalSpan, BOOL32 isMax);
|
||||
|
||||
|
||||
// Functions
|
||||
|
||||
void L2V_PrintPtr(lPtr_t lptr)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
LPTR_UNPACK(lptr, cu);
|
||||
L2V_PrintCU(&cu);
|
||||
}
|
||||
|
||||
void L2V_PrintCU(ContigUnpacked_t *cu)
|
||||
{
|
||||
if (cu->isNodePtr)
|
||||
printf("[Node]");
|
||||
else
|
||||
printf("[NAND]");
|
||||
|
||||
if (cu->hasSpanOF)
|
||||
printf("o");
|
||||
else
|
||||
printf("-");
|
||||
|
||||
if (cu->isNodePtr) {
|
||||
printf("[idx:%d][span:%d]", cu->u.nodeIdx, cu->span);
|
||||
} else {
|
||||
if (L2V_VBA_DEALLOC == cu->u.vba) {
|
||||
printf("[vba:DEALLOC][span:%d]", cu->span);
|
||||
} else {
|
||||
printf("[vba:%d][span:%d]", cu->u.vba, cu->span);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void L2V_PrintNode(lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize;
|
||||
lPtr_t thisPtr;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
L2V_PrintCU(&cu);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
}
|
||||
|
||||
|
||||
void L2V_PrintUsage(UInt32 tree)
|
||||
{
|
||||
UInt32 used, total, nodes, maxdepth;
|
||||
RootContig_t rc = L2V.Root[tree].rootContig;
|
||||
|
||||
used = total = nodes = maxdepth = 0;
|
||||
printf("digraph G {\n");
|
||||
if (ROOT_CONTIG_DEALLOC != rc)
|
||||
{
|
||||
maxdepth = L2V_GetUsage(L2V_IDX_TO_NODE(ROOT_CONTIG_GET_NODEIDX(rc)), &used, &total, &nodes, L2V_TREE_SIZE, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[NAND]r[vba:DEALLOC][span:32768]\n");
|
||||
}
|
||||
printf("}\n");
|
||||
printf("\nUsage tree %d: %.2f, nodes: %d, maxdepth: %d\n", tree, total ? (float)used/(float)total : 0, nodes, maxdepth);
|
||||
printf("Nodes calc: %d tally: %d\n\n", nodes, L2V.Root[tree].numNodes);
|
||||
if (nodes != L2V.Root[tree].numNodes)
|
||||
{
|
||||
WMR_PANIC("nodes (%d) != L2V.Root[tree].numNodes (%d)\n", nodes, L2V.Root[tree].numNodes);
|
||||
}
|
||||
}
|
||||
|
||||
static int L2V_GetUsage(lNode_t *node, UInt32 *used, UInt32 *total, UInt32 *nodes, UInt32 totalSpan, BOOL32 isMax)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
UInt32 sumSpan;
|
||||
lPtr_t thisPtr, maxNode;
|
||||
UInt32 depth, maxDepth, maxSpan;
|
||||
ContigUnpacked_t cu;
|
||||
UInt32 thisUsed = 0;
|
||||
|
||||
// Walk through
|
||||
(*nodes)++;
|
||||
maxDepth = 0;
|
||||
sumSpan = 0;
|
||||
|
||||
// Iterate through the node,
|
||||
L2V_PrintNode(node);
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
thisUsed += sizeof(lPtr_t);
|
||||
if (cu.hasSpanOF) thisUsed += sizeof(UInt16);
|
||||
if (cu.isNodePtr) {
|
||||
printf("%d -> %d;\n", (int)L2V_NODE_TO_IDX(node), cu.u.nodeIdx); // DOT output
|
||||
l2v_assert_ne(cu.u.nodeIdx, 65535);
|
||||
l2v_assert_ne(L2V_IDX_TO_NODE(cu.u.nodeIdx), node);
|
||||
l2v_assert_ne(cu.span, 0);
|
||||
depth = L2V_GetUsage(L2V_IDX_TO_NODE(cu.u.nodeIdx), used, total, nodes, cu.span, 0);
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
maxNode = thisPtr;
|
||||
maxSpan = cu.span;
|
||||
}
|
||||
}
|
||||
sumSpan += cu.span;
|
||||
l2v_assert_le(cu.span, 32768);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
*used += thisUsed;
|
||||
*total += sizeof(lNode_t);
|
||||
printf("%d [label=\"us:%.2f\\nsp:%.2f\",shape=box,style=filled,color=\"1.0 %.2f 1.0\"];\n", (int)L2V_NODE_TO_IDX(node), (float)thisUsed/sizeof(lNode_t), (float)totalSpan/L2V_TREE_SIZE, (float)thisUsed/sizeof(lNode_t)); // DOT output
|
||||
|
||||
if (sumSpan != totalSpan) {
|
||||
printf("Sum: %d, total: %d\n", sumSpan, totalSpan);
|
||||
L2V_PrintNode(node);
|
||||
}
|
||||
l2v_assert_eq(sumSpan, totalSpan);
|
||||
l2v_assert_ne(nOfs, 0);
|
||||
|
||||
#if PRINT_MAXPATH
|
||||
if (maxDepth && isMax) {
|
||||
printf("<-%d", maxNode.node.nodeIdx);
|
||||
L2V_GetUsage(L2V_LPTR_TO_NODE(maxNode), &nOfs, &nOfs, &nOfs, maxSpan, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return maxDepth+1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_PRINT_H__
|
||||
#define __L2V_PRINT_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void L2V_PrintPtr(lPtr_t lptr);
|
||||
extern void L2V_PrintCU(ContigUnpacked_t *cu);
|
||||
extern void L2V_PrintNode(lNode_t *node);
|
||||
extern void L2V_PrintUsage(UInt32 tree);
|
||||
|
||||
|
||||
#endif // __L2V_PRINT_H__
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#define AND_TRACE_LAYER FTL
|
||||
|
||||
#include "L2V_Repack.h"
|
||||
#include "L2V.h"
|
||||
#include "L2V_Types.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
|
||||
#define REPACK_MAX_NODES (L2V_TREE_SIZE/L2V_MIN_CONTIG_PER_NODE)
|
||||
#define REPACK_TREE_LOG_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
lNode_t *bottom[REPACK_MAX_NODES];
|
||||
UInt32 bottomSpan[REPACK_MAX_NODES];
|
||||
UInt32 bottomIdx;
|
||||
UInt32 bottom_nOfs;
|
||||
UInt32 bottom_nodeSize;
|
||||
#if REPACK_DATA_GATHERING
|
||||
UInt32 repackedTree[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 updSinceRepack[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 numNodesBef[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 numNodesAft[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 numNodeContBef[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 numNodeContAft[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 numNandCont[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 timeREP[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 timeCD[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 timeREB[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 repackTreeLogIdx;
|
||||
#endif
|
||||
} RepackCtx_t;
|
||||
|
||||
|
||||
// Static definitions
|
||||
static void CopyAndDestroy(RepackCtx_t *r, lNode_t *node);
|
||||
static int Rebuild(RepackCtx_t *r);
|
||||
static void ReplaceRoot(RepackCtx_t *r, UInt32 tree);
|
||||
static int CopyAndDestroyOneNode(RepackCtx_t *r, lNode_t *node, int nodeCount);
|
||||
|
||||
|
||||
UInt32 L2V_ForceRepack(void)
|
||||
{
|
||||
UInt32 best;
|
||||
UInt32 merit, bestMerit, i;
|
||||
|
||||
// Find best candidate; merit==updates
|
||||
bestMerit = 0;
|
||||
best = 0xffffffff;
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
if((L2V.Root[i].rootContig != ROOT_CONTIG_DEALLOC) && (L2V.Root[i].numNodes > 0) && (L2V.Root[i].updatesSinceRepack > 0))
|
||||
{
|
||||
merit = L2V.Root[i].updatesSinceRepack;
|
||||
if (merit >= bestMerit) {
|
||||
bestMerit = merit;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(L2V_CriticalMem)
|
||||
{
|
||||
l2v_assert_ne(best, 0xffffffff);
|
||||
l2v_assert_ne(bestMerit, 0);
|
||||
}
|
||||
|
||||
if(best != 0xffffffff)
|
||||
{
|
||||
L2V_Repack(best);
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
void L2V_PeriodicRepack()
|
||||
{
|
||||
// Check if it's appropriate or not
|
||||
if (L2V.RepackCounter < L2V_REPACK_PERIOD) {
|
||||
return;
|
||||
}
|
||||
L2V.RepackCounter = 0;
|
||||
|
||||
L2V_ForceRepack();
|
||||
}
|
||||
|
||||
|
||||
// WARNING: NOT REENTRANT
|
||||
static RepackCtx_t r;
|
||||
void L2V_Repack(UInt32 tree)
|
||||
{
|
||||
lNode_t *root;
|
||||
RootContig_t rc;
|
||||
#if REPACK_DATA_GATHERING
|
||||
UInt64 ticks, ticks_CD, ticks_REB;
|
||||
|
||||
ticks = WMR_CLOCK_TICKS();
|
||||
|
||||
// Log which tree we repacked
|
||||
if (r.repackTreeLogIdx >= REPACK_TREE_LOG_SIZE) {
|
||||
r.repackTreeLogIdx = 0;
|
||||
}
|
||||
r.repackedTree[r.repackTreeLogIdx] = tree;
|
||||
r.updSinceRepack[r.repackTreeLogIdx] = L2V.Root[tree].updatesSinceRepack;
|
||||
r.numNodesBef[r.repackTreeLogIdx] = L2V.Root[tree].numNodes;
|
||||
r.numNodeContBef[r.repackTreeLogIdx] = 0;
|
||||
r.numNodeContAft[r.repackTreeLogIdx] = 0;
|
||||
r.numNandCont[r.repackTreeLogIdx] = 0;
|
||||
|
||||
#endif
|
||||
|
||||
rc = L2V.Root[tree].rootContig;
|
||||
|
||||
// Trying to repack a rootptr? Abort...
|
||||
if (ROOT_CONTIG_DEALLOC == rc) {
|
||||
return;
|
||||
}
|
||||
|
||||
WMR_TRACE_1(Repack, START, tree);
|
||||
|
||||
// Up tree version for search-update coherency
|
||||
L2V.treeVersion++;
|
||||
|
||||
// Create list of new bottom layer
|
||||
r.bottomIdx = 0;
|
||||
r.bottom_nOfs = 0;
|
||||
r.bottom_nodeSize = L2V_NODE_SIZE;
|
||||
WMR_MEMSET(r.bottom, 0, REPACK_MAX_NODES * sizeof(r.bottom[0]));
|
||||
WMR_MEMSET(r.bottomSpan, 0, REPACK_MAX_NODES * sizeof(r.bottomSpan[0]));
|
||||
|
||||
// Recurse and destroy
|
||||
root = L2V_IDX_TO_NODE(ROOT_CONTIG_GET_NODEIDX(rc));
|
||||
#if REPACK_DATA_GATHERING
|
||||
ticks_CD = WMR_CLOCK_TICKS();
|
||||
#endif
|
||||
CopyAndDestroy(&r, root);
|
||||
#if REPACK_DATA_GATHERING
|
||||
ticks_CD = WMR_CLOCK_TICKS() - ticks_CD;
|
||||
#endif
|
||||
|
||||
l2v_assert_ne(r.bottom_nOfs, 0);
|
||||
|
||||
#if REPACK_DATA_GATHERING
|
||||
ticks_REB = WMR_CLOCK_TICKS();
|
||||
#endif
|
||||
// Rebuild hierarchy
|
||||
L2V.Root[tree].numNodes = Rebuild(&r);
|
||||
#if REPACK_DATA_GATHERING
|
||||
ticks_REB = WMR_CLOCK_TICKS() - ticks_REB;
|
||||
#endif
|
||||
|
||||
// Replace root
|
||||
ReplaceRoot(&r, tree);
|
||||
|
||||
// Clear repack counter
|
||||
L2V.Root[tree].updatesSinceRepack = 0;
|
||||
|
||||
#if REPACK_DATA_GATHERING
|
||||
ticks = WMR_CLOCK_TICKS() - ticks;
|
||||
|
||||
r.numNodesAft[r.repackTreeLogIdx] = L2V.Root[tree].numNodes;
|
||||
r.timeREP[r.repackTreeLogIdx] = (UInt32)(ticks / WMR_GET_TICKS_PER_US());
|
||||
r.timeCD[r.repackTreeLogIdx] = (UInt32)(ticks_CD / WMR_GET_TICKS_PER_US());
|
||||
r.timeREB[r.repackTreeLogIdx] = (UInt32)(ticks_REB / WMR_GET_TICKS_PER_US());
|
||||
|
||||
r.repackTreeLogIdx++;
|
||||
|
||||
#endif
|
||||
|
||||
WMR_TRACE_0(Repack, END);
|
||||
}
|
||||
|
||||
|
||||
static int CopyAndDestroyOneNode(RepackCtx_t *r, lNode_t *node, int nodeCount)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
// Would be full? Move along...
|
||||
if ((r->bottom_nOfs + _L2V_CONTIG_SIZE(cu)) > r->bottom_nodeSize) {
|
||||
r->bottomIdx++;
|
||||
l2v_assert_lt(r->bottomIdx, REPACK_MAX_NODES);
|
||||
}
|
||||
|
||||
// Allocate node if necessary
|
||||
if (NULL == r->bottom[r->bottomIdx]) {
|
||||
// Allocate...
|
||||
r->bottom[r->bottomIdx] = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
r->bottom_nOfs = 0;
|
||||
r->bottom_nodeSize = L2V_NODE_SIZE;
|
||||
}
|
||||
|
||||
// Copy out
|
||||
_L2V_NODE_PUSH_CONTIG(r->bottom[r->bottomIdx], r->bottom_nOfs, r->bottom_nodeSize, cu);
|
||||
r->bottomSpan[r->bottomIdx] += cu.span;
|
||||
l2v_assert_le(cu.span, L2V_TREE_SIZE);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
// Free the node
|
||||
_L2V_FreeNode(node);
|
||||
nodeCount--;
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
|
||||
static void CopyAndDestroy(RepackCtx_t *r, lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
// Recurse
|
||||
#if REPACK_DATA_GATHERING
|
||||
r->numNodeContBef[r->repackTreeLogIdx]++;
|
||||
#endif
|
||||
CopyAndDestroy(r, L2V_IDX_TO_NODE(cu.u.nodeIdx));
|
||||
} else {
|
||||
#if REPACK_DATA_GATHERING
|
||||
r->numNandCont[r->repackTreeLogIdx]++;
|
||||
#endif
|
||||
// Would be full? Move along...
|
||||
if ((r->bottom_nOfs + _L2V_CONTIG_SIZE(cu)) > r->bottom_nodeSize) {
|
||||
r->bottomIdx++;
|
||||
l2v_assert_lt(r->bottomIdx, REPACK_MAX_NODES);
|
||||
}
|
||||
|
||||
// Allocate node if necessary
|
||||
if (NULL == r->bottom[r->bottomIdx]) {
|
||||
// Allocate...
|
||||
r->bottom[r->bottomIdx] = _L2V_AllocNode();
|
||||
r->bottom_nOfs = 0;
|
||||
r->bottom_nodeSize = L2V_NODE_SIZE;
|
||||
}
|
||||
|
||||
// Copy out
|
||||
_L2V_NODE_PUSH_CONTIG(r->bottom[r->bottomIdx], r->bottom_nOfs, r->bottom_nodeSize, cu);
|
||||
r->bottomSpan[r->bottomIdx] += cu.span;
|
||||
l2v_assert_le(cu.span, L2V_TREE_SIZE);
|
||||
}
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
// Free the node
|
||||
_L2V_FreeNode(node);
|
||||
}
|
||||
|
||||
|
||||
static int Rebuild(RepackCtx_t *r)
|
||||
{
|
||||
lNode_t *thisBranch;
|
||||
UInt32 nOfs, nodeSize, thisSpan, i, branchIdx;
|
||||
ContigUnpacked_t cu;
|
||||
int nodeCount;
|
||||
lNode_t *tempBottomNode;
|
||||
|
||||
nodeCount = r->bottomIdx + 1;
|
||||
|
||||
while (r->bottomIdx > 0) {
|
||||
thisBranch = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
nOfs = 0;
|
||||
nodeSize = L2V_NODE_SIZE;
|
||||
thisSpan = 0;
|
||||
branchIdx = 0;
|
||||
|
||||
// Rebuild this layer
|
||||
for (i = 0; i < r->bottomIdx; i++) {
|
||||
cu.isNodePtr = 1;
|
||||
cu.u.nodeIdx = L2V_NODE_TO_IDX(r->bottom[i]);
|
||||
cu.span = r->bottomSpan[i];
|
||||
|
||||
if ((nOfs + _L2V_CONTIG_SIZE(cu)) > nodeSize) {
|
||||
// Place it down and get a new one
|
||||
r->bottom[branchIdx] = thisBranch;
|
||||
r->bottomSpan[branchIdx] = thisSpan;
|
||||
branchIdx++;
|
||||
thisBranch = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
nOfs = 0;
|
||||
nodeSize = L2V_NODE_SIZE;
|
||||
thisSpan = 0;
|
||||
}
|
||||
|
||||
_L2V_NODE_PUSH_CONTIG(thisBranch, nOfs, nodeSize, cu);
|
||||
thisSpan += cu.span;
|
||||
#if REPACK_DATA_GATHERING
|
||||
r->numNodeContAft[r->repackTreeLogIdx]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
l2v_assert_ne(nOfs, 0);
|
||||
|
||||
r->bottom[branchIdx] = thisBranch;
|
||||
r->bottomSpan[branchIdx] = thisSpan;
|
||||
tempBottomNode = r->bottom[r->bottomIdx];
|
||||
// Get ready for the next round
|
||||
r->bottomIdx = branchIdx;
|
||||
r->bottom_nOfs = nOfs;
|
||||
r->bottom_nodeSize = nodeSize;
|
||||
WMR_MEMSET(&(r->bottom[branchIdx + 1]), 0, (REPACK_MAX_NODES - (branchIdx + 1)) * sizeof(r->bottom[0]));
|
||||
WMR_MEMSET(&(r->bottomSpan[branchIdx + 1]), 0, (REPACK_MAX_NODES - (branchIdx + 1)) * sizeof(r->bottomSpan[0]));
|
||||
|
||||
// repack the remainder to ensure we do not waste extra node
|
||||
nodeCount = CopyAndDestroyOneNode(r, tempBottomNode, nodeCount);
|
||||
|
||||
// Make sure the repack didn't munge the root node's spans
|
||||
if (0 == r->bottomIdx) {
|
||||
l2v_assert_eq(r->bottomSpan[r->bottomIdx], L2V_TREE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
|
||||
static void ReplaceRoot(RepackCtx_t *r, UInt32 tree)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
l2v_assert_eq(r->bottomIdx, 0);
|
||||
cu.u.nodeIdx = L2V_NODE_TO_IDX(r->bottom[0]);
|
||||
cu.isNodePtr = 1;
|
||||
L2V.Root[tree].rootContig = ROOT_CONTIG_PACK(cu);
|
||||
if(ROOT_CONTIG_DEALLOC == L2V.Root[tree].rootContig)
|
||||
{
|
||||
L2V_root_depth[tree] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_REPACK_H__
|
||||
#define __L2V_REPACK_H__
|
||||
|
||||
|
||||
#include "WMROAM.h"
|
||||
|
||||
// Functions
|
||||
|
||||
extern void L2V_PeriodicRepack(void);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
extern UInt32 L2V_ForceRepack(void);
|
||||
|
||||
#endif // __L2V_REPACK_H__
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
|
||||
void L2V_Search_Init(L2V_SearchCtx_t *c)
|
||||
{
|
||||
c->next_lba = 0xffffffff;
|
||||
c->last_node = NULL;
|
||||
c->span = 0;
|
||||
}
|
||||
|
||||
|
||||
static BOOL32 HitCache(L2V_SearchCtx_t *c)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
|
||||
if ((c->treeVersion == L2V.treeVersion) && (c->lba == c->next_lba) && (NULL != c->last_node)) {
|
||||
// Sequential HIT
|
||||
_L2V_NODE_ITERATE_RESUME(c->last_node, c->next_nOfs, c->nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr)
|
||||
break;
|
||||
|
||||
c->vba = cu.u.vba;
|
||||
c->fromStart = 0;
|
||||
c->span = cu.span;
|
||||
|
||||
_L2V_NODE_ITERATE_NEXT(c->next_nOfs); // This will move nOfs along
|
||||
c->next_lba = c->lba + c->span;
|
||||
return TRUE32;
|
||||
|
||||
} _L2V_NODE_ITERATE_END_NOP;
|
||||
}
|
||||
|
||||
// Clear search history
|
||||
c->next_lba = 0xffffffff;
|
||||
c->last_node = NULL;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
void L2V_Search(L2V_SearchCtx_t *c)
|
||||
{
|
||||
UInt32 targTree, targTofs;
|
||||
UInt32 thisStart, thisMax;
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node, and node effective size
|
||||
ContigUnpacked_t cu, thiscu;
|
||||
lNode_t *node = NULL;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
if (HitCache(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine first root
|
||||
targTree = c->lba >> L2V_TREE_BITS;
|
||||
targTofs = c->lba & L2V_TREE_MASK;
|
||||
l2v_assert_lt(targTree, L2V.numRoots);
|
||||
|
||||
c->level = 0;
|
||||
thisStart = 0;
|
||||
c->vba = L2V_VBA_DEALLOC;
|
||||
ROOT_CONTIG_UNPACK(L2V.Root[targTree].rootContig, cu);
|
||||
thiscu.span = L2V_TREE_SIZE;
|
||||
c->next_nOfs = 0;
|
||||
|
||||
// Search from top down
|
||||
while (c->level < L2V_MAX_TREE_DEPTH) {
|
||||
// Down and next
|
||||
// Decode node pointer
|
||||
if (!cu.isNodePtr) {
|
||||
// Terminal case--pointer to physical location; calculate relative offset...
|
||||
c->vba = cu.u.vba;
|
||||
c->fromStart = targTofs - thisStart;
|
||||
if (cu.u.vba < L2V_VBA_SPECIAL) {
|
||||
c->vba += c->fromStart;
|
||||
}
|
||||
c->span = thiscu.span - c->fromStart;
|
||||
// Set up return case for sequential searching
|
||||
c->last_node = node;
|
||||
c->next_lba = c->lba + c->span;
|
||||
c->treeVersion = L2V.treeVersion;
|
||||
// c->next_nOfs is populated from code below, i.e. the previous iteration of this while loop
|
||||
|
||||
// Is it getting really big? Do some preventative maintenence...
|
||||
if (c->level >= L2V_TREE_DEPTH_REPACK) {
|
||||
L2V_Repack(targTree);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk through
|
||||
node = L2V_IDX_TO_NODE(cu.u.nodeIdx);
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, thiscu, thisPtr) {
|
||||
// Calculate endpoint
|
||||
thisMax = thisStart + thiscu.span;
|
||||
|
||||
// Are we in range?
|
||||
if (targTofs < thisMax) {
|
||||
// HIT! (Left-hand side implied by order of search.)
|
||||
cu = thiscu;
|
||||
_L2V_NODE_ITERATE_NEXT(nOfs);
|
||||
c->next_nOfs = nOfs;
|
||||
c->nodeSize = nodeSize;
|
||||
goto decodePtr;
|
||||
}
|
||||
|
||||
// Move along in the node
|
||||
thisStart = thisMax;
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
WMR_PANIC("NAND index: bad tree: targTofs %d, level %d\n", targTofs, c->level);
|
||||
|
||||
decodePtr:
|
||||
// Resume here so we can check the while() condition
|
||||
c->level++;
|
||||
}
|
||||
|
||||
l2v_assert(0); // Should never get here; otherwise, the tree is too deep (or recursive or pointing to randomness)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Print.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
L2V_t L2V;
|
||||
|
||||
|
||||
#define LAST_TREE_TEST 16
|
||||
#define SIMPLE_SIZE (L2V_TREE_SIZE*LAST_TREE_TEST)
|
||||
|
||||
|
||||
// Prototypes
|
||||
static void RandomTest(void);
|
||||
static void SequentialTest(void);
|
||||
static void Simple_Init(void);
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vba);
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vba);
|
||||
|
||||
void Usage(int argc, char** argv)
|
||||
{
|
||||
printf("Usage: %s s OR %s r (for sequential and random, respectively\n", argv[0], argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int test = 0;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// we should add an option to change a pool size via command line
|
||||
L2V_nodepool_mem = DEFAULT_L2V_NODEPOOL_MEM;
|
||||
|
||||
//L2V_Init(SIMPLE_SIZE, 32768, 32768);
|
||||
//L2V_Init(SIMPLE_SIZE, 16384, 32768);
|
||||
//L2V_Init(SIMPLE_SIZE, 16384, 16384);
|
||||
//L2V_Init(SIMPLE_SIZE, 8192, 8192);
|
||||
L2V_Init(SIMPLE_SIZE, 8200, 8192);
|
||||
|
||||
if (argc == 2) {
|
||||
if ('r' == argv[1][0]) {
|
||||
test = 0;
|
||||
} else if ('s' == argv[1][0]) {
|
||||
test = 1;
|
||||
} else {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
}
|
||||
if (argc > 2) {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
|
||||
if (0 == test) {
|
||||
RandomTest();
|
||||
} else {
|
||||
SequentialTest();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define MAXLEN 512
|
||||
static void RandomTest() {
|
||||
UInt32 lba, size, vba;
|
||||
UInt32 i, svba;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
sranddev();
|
||||
|
||||
while (1) {
|
||||
lba = rand() % ((L2V_TREE_SIZE*LAST_TREE_TEST)-MAXLEN);
|
||||
size = (rand() % (MAXLEN-1))+1;
|
||||
vba = rand() % ((1UL<<(L2V.bits.vba-1))-size-1);
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vba:%d]\n", lba, size, vba);
|
||||
L2V_Update(lba, size, vba, 0);
|
||||
Simple_Update(lba, size, vba);
|
||||
//printf("\n");
|
||||
//L2V_PrintNode(L2V_LPTR_TO_NODE(L2V.Tree[0]));
|
||||
L2V_PrintUsage(lba/L2V_TREE_SIZE);
|
||||
|
||||
|
||||
// Validate entire range
|
||||
int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svba);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svba != c.vba) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vba:%d\n", svba);
|
||||
printf("Lookup vba:%d\n", c.vba);
|
||||
}
|
||||
l2v_assert_eq(svba, c.vba);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
|
||||
#if 0
|
||||
if (repack++ > 10) {
|
||||
printf("Repacking tree %d...\n", nextRepack);
|
||||
L2V_Repack(nextRepack);
|
||||
L2V_PrintUsage(nextRepack);
|
||||
repack = 0;
|
||||
nextRepack = (nextRepack + 1) % LAST_TREE_TEST;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void SequentialTest() {
|
||||
UInt32 lba, size, vba;
|
||||
UInt32 i, svba;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
sranddev();
|
||||
|
||||
lba = 0;
|
||||
size = 0;
|
||||
vba = 1;
|
||||
|
||||
while (1) {
|
||||
lba += size;
|
||||
size = (rand() % (MAXLEN-1))+1;
|
||||
if ((lba + size) >= L2V_TREE_SIZE) {
|
||||
lba = 0;
|
||||
}
|
||||
if ((rand() & 3) == 0) {
|
||||
vba = rand() % ((1UL<<(L2V.bits.vba-1))-size-1);
|
||||
}
|
||||
while (((vba + size) & ((1<<(L2V.bits.vba-1))-1)) < vba) {
|
||||
vba = rand() % ((1UL<<(L2V.bits.vba-1))-size-1);
|
||||
}
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vba:%d]\n", lba, size, vba);
|
||||
L2V_Update(lba, size, vba, 0);
|
||||
Simple_Update(lba, size, vba);
|
||||
L2V_PrintUsage(lba/L2V_TREE_SIZE);
|
||||
vba += size;
|
||||
|
||||
|
||||
// Validate entire range
|
||||
int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svba);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svba != c.vba) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vba:%d\n", svba);
|
||||
printf("Lookup vba:%d\n", c.vba);
|
||||
}
|
||||
l2v_assert_eq(svba, c.vba);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 Simple_vba[SIMPLE_SIZE];
|
||||
|
||||
static void Simple_Init()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_vba[i] = L2V_VBA_DEALLOC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vba)
|
||||
{
|
||||
while (size) {
|
||||
Simple_vba[lba] = vba;
|
||||
|
||||
// Iterate
|
||||
lba++;
|
||||
if (vba < L2V_VBA_SPECIAL) {
|
||||
vba++;
|
||||
}
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vba)
|
||||
{
|
||||
*vba = Simple_vba[lba];
|
||||
}
|
||||
|
||||
void Outside_L2V_ValidUp(UInt32 vba, UInt32 count)
|
||||
{
|
||||
}
|
||||
void Outside_L2V_ValidDown(UInt32 vba, UInt32 count)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
OBJS=L2V_Test.o L2V_Funcs.o L2V_Init.o L2V_Mem.o L2V_Search.o L2V_Update.o L2V_Types.o L2V_Print.o L2V_Repack.o L2V_Free.o L2V_FindFrag.o WMROAM.o
|
||||
LINK_TARGET=L2V_Test
|
||||
REBUILDABLES=$(OBJS) $(LINK_TARGET)
|
||||
|
||||
.PHONY: all
|
||||
all: copythem $(LINK_TARGET) cleanthem
|
||||
#
|
||||
|
||||
.PHONY: copythem
|
||||
copythem:
|
||||
cp WMROAM-test.h WMROAM.h
|
||||
cp WMROAM-test.c WMROAM.c
|
||||
cp WMRFeatures-test.h WMRFeatures.h
|
||||
|
||||
.PHONY: cleanthem
|
||||
cleanthem:
|
||||
rm WMROAM.c WMROAM.h WMRFeatures.h
|
||||
|
||||
$(LINK_TARGET): $(OBJS)
|
||||
gcc -g -o $@ $^ -Wall
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(REBUILDABLES)
|
||||
rm WMROAM.c WMROAM.h WMRFeatures.h
|
||||
|
||||
%.o: %.c
|
||||
gcc -g -o $@ -c $< -Wall -I.
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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 "L2V_Defines.h"
|
||||
#include "L2V_Types.h"
|
||||
#include "L2V.h"
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig(lNodeBig_t *big, ContigUnpacked_t *cu)
|
||||
{
|
||||
Int32 last = ((Int32)big->max)-1;
|
||||
l2v_assert_ne(cu->span, 0);
|
||||
|
||||
if (!cu->isNodePtr && (last >= 0) && !big->cu[last].isNodePtr && (
|
||||
((cu->u.vba < L2V_VBA_SPECIAL) && ((big->cu[last].u.vba+big->cu[last].span) == cu->u.vba))
|
||||
|| ((cu->u.vba >= L2V_VBA_SPECIAL) && (big->cu[last].u.vba == cu->u.vba))))
|
||||
{
|
||||
big->cu[last].span += cu->span;
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
big->cu[big->max] = *cu;
|
||||
big->max++;
|
||||
|
||||
if (cu->isNodePtr) {
|
||||
l2v_assert_lt(cu->u.nodeIdx, L2V_NODEPOOL_COUNT);
|
||||
}
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig_Node(lNodeBig_t *big, UInt32 nodeIdx, UInt32 span)
|
||||
{
|
||||
big->cu[big->max].isNodePtr = 1;
|
||||
big->cu[big->max].u.nodeIdx = nodeIdx;
|
||||
big->cu[big->max].span = span;
|
||||
big->max++;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig_Nand(lNodeBig_t *big, UInt32 vba, UInt32 span)
|
||||
{
|
||||
Int32 last = ((Int32)big->max)-1;
|
||||
l2v_assert_ne(span, 0);
|
||||
|
||||
if ((last >= 0) && !big->cu[last].isNodePtr && (
|
||||
((vba < L2V_VBA_SPECIAL) && ((big->cu[last].u.vba+big->cu[last].span) == vba))
|
||||
|| ((vba >= L2V_VBA_SPECIAL) && (big->cu[last].u.vba == vba))))
|
||||
{
|
||||
big->cu[last].span += span;
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
big->cu[big->max].isNodePtr = 0;
|
||||
big->cu[big->max].u.vba = vba;
|
||||
big->cu[big->max].span = span;
|
||||
big->max++;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_TYPES_H__
|
||||
#define __L2V_TYPES_H__
|
||||
|
||||
|
||||
#include "WMROAM.h"
|
||||
#include "L2V_Defines.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
|
||||
// Pointer type: can point to NAND, or to a subtree
|
||||
// Bits: 0=isNodePtr, 1=hasSpanOF.
|
||||
// isNodePtr=0: vba:L2V.bits.vba, span:L2V.bits.nand_span
|
||||
// isNodePtr=1: nodeIdx:L2V.bits.nodeIdx, span:L2V.bits.node_span
|
||||
// hasSpanOF: fetch 2 bytes from the right end of the node
|
||||
|
||||
typedef UInt32 lPtr_t;
|
||||
#define LPTR_IS_NODEPTR(_lptr) ((_lptr) & 1)
|
||||
#define LPTR_HASSPANOF(_lptr) (((_lptr) & 2) >> 1)
|
||||
#define LPTR_PACK_NAND(_cu) ( \
|
||||
(((_cu).hasSpanOF & 1) << 1) | \
|
||||
(((_cu).u.vba & (((1UL<<L2V.bits.vba)-1))) << 2) | \
|
||||
((((_cu).span-1) & ((1UL<<L2V.bits.nand_span)-1)) << (2+L2V.bits.vba)) \
|
||||
)
|
||||
#define LPTR_PACK_NODE(_cu) ( \
|
||||
1 | \
|
||||
(((_cu).hasSpanOF & 1) << 1) | \
|
||||
(((_cu).u.nodeIdx & ((1UL<<L2V.bits.nodeIdx)-1)) << 2) | \
|
||||
((((_cu).span-1) & (((1UL<<L2V.bits.node_span)-1))) << (2+L2V.bits.nodeIdx)) \
|
||||
)
|
||||
#define LPTR_UNPACK_NAND(_lptr, _cu) do { \
|
||||
(_cu).isNodePtr = 0; \
|
||||
(_cu).hasSpanOF = ((_lptr) >> 1) & 1; \
|
||||
(_cu).u.vba = ((_lptr) >> 2) & ((1UL<<L2V.bits.vba)-1); \
|
||||
(_cu).span = ((_lptr) >> (2+L2V.bits.vba)) & ((1UL<<L2V.bits.nand_span)-1); \
|
||||
} while (0)
|
||||
#define LPTR_UNPACK_NODE(_lptr, _cu) do { \
|
||||
(_cu).isNodePtr = 1; \
|
||||
(_cu).hasSpanOF = ((_lptr) >> 1) & 1; \
|
||||
(_cu).u.nodeIdx = ((_lptr) >> 2) & ((1UL<<L2V.bits.nodeIdx)-1); \
|
||||
(_cu).span = ((_lptr) >> (2+L2V.bits.nodeIdx)) & ((1UL<<L2V.bits.node_span)-1); \
|
||||
} while (0)
|
||||
#define LPTR_GET_NODEIDX(_lptr) (((_lptr) >> 2) & ((1UL<<L2V.bits.nodeIdx)-1))
|
||||
#define LPTR_UNPACK(_lptr, _cu) do { \
|
||||
if LPTR_IS_NODEPTR(_lptr) { \
|
||||
LPTR_UNPACK_NODE(_lptr, _cu); \
|
||||
} else { \
|
||||
LPTR_UNPACK_NAND(_lptr, _cu); \
|
||||
} \
|
||||
} while (0)
|
||||
#define LPTR_PACK_NAND_SPANOF(_span) ((_span-1) >> L2V.bits.nand_span)
|
||||
#define LPTR_PACK_NODE_SPANOF(_span) ((_span-1) >> L2V.bits.node_span)
|
||||
|
||||
typedef UInt16 RootContig_t;
|
||||
#define ROOT_CONTIG_DEALLOC (0xFFFF)
|
||||
#define ROOT_CONTIG_GET_NODEIDX(rc) (rc)
|
||||
#define ROOT_CONTIG_PACK(_cu) ((_cu).isNodePtr ? (_cu).u.nodeIdx : ROOT_CONTIG_DEALLOC) // might have to type cast to UInt16
|
||||
#define ROOT_CONTIG_UNPACK(_rc, _cu) do { \
|
||||
(_cu).hasSpanOF = 0; /* dont care */ \
|
||||
if (ROOT_CONTIG_DEALLOC == (_rc)) \
|
||||
{ \
|
||||
(_cu).u.vba = L2V_VBA_DEALLOC; \
|
||||
(_cu).isNodePtr = 0; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(_cu).u.nodeIdx = (_rc); \
|
||||
(_cu).isNodePtr = 1; \
|
||||
} \
|
||||
(_cu).span = L2V_TREE_SIZE; \
|
||||
}while(0);
|
||||
|
||||
typedef struct {
|
||||
UInt32 isNodePtr; // Values: 0, 1 (true)... must not be any other value
|
||||
UInt32 hasSpanOF; // Values: 0, 1 (true)... ditto
|
||||
union {
|
||||
UInt32 vba;
|
||||
UInt32 nodeIdx;
|
||||
} u;
|
||||
UInt32 span;
|
||||
} ContigUnpacked_t;
|
||||
|
||||
|
||||
// Node type: union for dynamic and fixed node types (and FreePool linkage)
|
||||
typedef union _lNode_t {
|
||||
union _lNode_t *nextFreePtr;
|
||||
|
||||
UInt8 bytes[L2V_NODE_SIZE];
|
||||
} lNode_t;
|
||||
WMR_CASSERT(L2V_NODE_SIZE == sizeof(lNode_t), lNode_t_size_matches);
|
||||
|
||||
#define L2V_LNODEBIG_MAX (L2V_MAX_CONTIG_PER_NODE+(L2V_SUCKUP_CHILDREN_MAX*2)+5)
|
||||
typedef struct {
|
||||
ContigUnpacked_t cu[L2V_LNODEBIG_MAX];
|
||||
UInt32 start;
|
||||
UInt32 max;
|
||||
} lNodeBig_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
lNode_t *Node; // Node pool allocated with malloc()
|
||||
lNode_t *FreePtr;
|
||||
UInt32 FreeCount;
|
||||
} FTLight_NodePool_t;
|
||||
|
||||
typedef struct{
|
||||
lNodeBig_t *tempNodeEntries;
|
||||
UInt8 *isEntryAvailable;
|
||||
UInt32 poolSize;
|
||||
} tempNodePool_t;
|
||||
|
||||
typedef struct {
|
||||
RootContig_t rootContig;
|
||||
UInt16 numNodes;
|
||||
UInt16 updatesSinceRepack; // 2 bytes because upper bounded by L2V_REPACK_PERIOD(which is 200)
|
||||
} Root_t;
|
||||
|
||||
typedef struct {
|
||||
UInt32 node_span;
|
||||
UInt32 nodeIdx;
|
||||
UInt32 nand_span;
|
||||
UInt32 vba;
|
||||
} L2V_Bits_t;
|
||||
|
||||
typedef struct {
|
||||
// Special vbas
|
||||
UInt32 special;
|
||||
UInt32 dealloc;
|
||||
} L2V_vba_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
// Logical space
|
||||
UInt32 numRoots;
|
||||
Root_t *Root;
|
||||
UInt32 RepackCounter;
|
||||
UInt32 treeVersion;
|
||||
|
||||
// Physical space
|
||||
UInt32 max_sb;
|
||||
UInt32 vbas_per_sb;
|
||||
|
||||
// Bit arrangements
|
||||
L2V_Bits_t bits;
|
||||
// Special VBAs
|
||||
L2V_vba_t vba;
|
||||
|
||||
// Memory
|
||||
FTLight_NodePool_t Pool;
|
||||
} L2V_t;
|
||||
|
||||
typedef struct {
|
||||
// Input:
|
||||
UInt32 lba;
|
||||
|
||||
// Output:
|
||||
UInt32 fromStart; // blocks from start of treeSpan
|
||||
UInt32 vba;
|
||||
UInt32 span;
|
||||
|
||||
// Internal state:
|
||||
lNode_t *last_node;
|
||||
UInt32 next_lba;
|
||||
UInt32 next_nOfs;
|
||||
UInt32 nodeSize;
|
||||
UInt32 level;
|
||||
UInt32 treeVersion;
|
||||
} L2V_SearchCtx_t;
|
||||
|
||||
|
||||
// Helper functions
|
||||
|
||||
extern BOOL32 _L2V_NodeBig_PushContig(lNodeBig_t *big, ContigUnpacked_t *cu); // True: compressed with left
|
||||
extern BOOL32 _L2V_NodeBig_PushContig_Node(lNodeBig_t *big, UInt32 nodeIdx, UInt32 span); // True: compress with left (always false)
|
||||
extern BOOL32 _L2V_NodeBig_PushContig_Nand(lNodeBig_t *big, UInt32 vba, UInt32 span); // True: compressed with left
|
||||
#define _L2V_NodeBig_WillCompress(_big, _vba, _span) \
|
||||
((_big.max > 0) && (!_big.cu[_big.max-1].isNodePtr) && \
|
||||
(((_vba < L2V_VBA_SPECIAL) && ((_big.cu[_big.max-1].u.vba+_big.cu[_big.max-1].span) == _vba)) \
|
||||
|| ((_vba >= L2V_VBA_SPECIAL) && (_big.cu[_big.max-1].u.vba == _vba))))
|
||||
|
||||
|
||||
#endif // __L2V_TYPES_H__
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __L2V_VALID_H__
|
||||
#define __L2V_VALID_H__
|
||||
|
||||
|
||||
#include "L2V_Defines.h"
|
||||
|
||||
#if L2V_TRACK_VALID!=0
|
||||
// Implemented in the user of L2V
|
||||
extern void Outside_L2V_ValidUp(UInt32 vba, UInt32 count);
|
||||
extern void Outside_L2V_ValidDown(UInt32 vba, UInt32 count);
|
||||
#else
|
||||
#error L2V valid tracking must be on
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __L2V_VALID_H__
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#define ENABLE_L2V_TREE (1)
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Author: Daniel J. Post (djp), dpost@apple.com
|
||||
|
||||
#include "WMROAM.h"
|
||||
|
||||
|
||||
void *WMR_MALLOC(UInt32 size)
|
||||
{
|
||||
void * ptr = malloc(size);
|
||||
if (ptr)
|
||||
{
|
||||
WMR_MEMSET(ptr, 0, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __WMROAM_H__
|
||||
#define __WMROAM_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UInt32 uint32_t
|
||||
#define Int32 int32_t
|
||||
#define UInt16 uint16_t
|
||||
#define Int16 int16_t
|
||||
#define UInt8 uint8_t
|
||||
#define Int8 int8_t
|
||||
#define BOOL32 bool
|
||||
#define TRUE32 true
|
||||
#define FALSE32 false
|
||||
|
||||
#define _WMR_ASSERT(e, file, line) { printf("%s:%u: failed assertion '%s'\nWaiting for debugger...\n", file, line, e); abort(); }
|
||||
#define WMR_ASSERT(e) if (!(e)) _WMR_ASSERT(#e, __FILE__, __LINE__)
|
||||
#define WMR_PANIC(format, args...) { printf(format , ##args); abort(); }
|
||||
#define WMR_MEMSET(a, b, c) memset(a, b, c)
|
||||
#define WMR_FREE(x, y) free(x)
|
||||
|
||||
#define WMR_CASSERT(x, name) typedef char __WMR_CASSERT_##name[(x) ? 1 : -1]
|
||||
#define WMR_OFFSETOF(type, field) ((size_t)(&((type *)0)->field))
|
||||
|
||||
#define WMR_LOG2(x) (31UL - __builtin_clz((UInt32)(x)))
|
||||
#define WMR_MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
extern void *WMR_MALLOC(UInt32 size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_TRACE_*
|
||||
//
|
||||
// Compile-time tracepoints (not supported)
|
||||
//
|
||||
#define WMR_TRACE_0(...)
|
||||
#define WMR_TRACE_1(...)
|
||||
#define WMR_TRACE_2(...)
|
||||
#define WMR_TRACE_3(...)
|
||||
#define WMR_TRACE_4(...)
|
||||
#define WMR_TRACE_IST_0(...)
|
||||
#define WMR_TRACE_IST_1(...)
|
||||
#define WMR_TRACE_IST_2(...)
|
||||
#define WMR_TRACE_IST_3(...)
|
||||
#define WMR_TRACE_IST_4(...)
|
||||
|
||||
#endif // __WMROAM_H__
|
||||
@@ -0,0 +1,15 @@
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
|
||||
while ($idx < $max)
|
||||
set $t = sftl.sb[$idx].type
|
||||
if (3 == $t)
|
||||
set $a = sftl.sb[$idx].validLbas
|
||||
set $b = sftl.dbg.validSums[$idx]
|
||||
if ($a != $b)
|
||||
printf "%d: %d <-> %d; %2.5f\n", $idx, $a, $b, ((float)$a)/(float)$b
|
||||
end
|
||||
end
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
set $sb = 0
|
||||
set $bank = 0
|
||||
set $sb_max = mcxt.dev.blocks_per_cau
|
||||
set $bank_max = mcxt.dev.num_of_banks
|
||||
set $good = 0
|
||||
set $bad = 0
|
||||
|
||||
while ($sb < $sb_max)
|
||||
set $bank = 0
|
||||
set $base = mcxt.r_gen.bytes_per_vbn_bitmap * $sb
|
||||
|
||||
while ($bank < $bank_max)
|
||||
if (mcxt.v2p_bitmap[$base + ($bank >> 3)] & (1 << ($bank % 8)))
|
||||
set $good = $good + 1
|
||||
else
|
||||
set $bad = $bad + 1
|
||||
end
|
||||
|
||||
set $bank = $bank + 1
|
||||
end
|
||||
|
||||
set $sb = $sb + 1
|
||||
end
|
||||
|
||||
printf "Good blocks: %d\n", $good
|
||||
printf "Bad blocks: %d\n", $bad
|
||||
printf "Total blocks: %d\n", ($good + $bad)
|
||||
printf "Total FTL blocks: %d\n", (sftl.__geom.max_sb * sftl.__geom.num_banks)
|
||||
printf "Bad block FTL percentage: %.3f\n", ((float)$bad * 100.0 / (sftl.__geom.max_sb * sftl.__geom.num_banks))
|
||||
@@ -0,0 +1,67 @@
|
||||
set $unknown = 0
|
||||
set $erased = 0
|
||||
set $pending = 0
|
||||
set $ebu = 0
|
||||
set $data = 0
|
||||
set $data_cur = 0
|
||||
set $data_gc = 0
|
||||
set $data_pending_gc = 0
|
||||
set $cxt = 0
|
||||
set $dead = 0
|
||||
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
while ($idx < $max)
|
||||
set $t = sftl.sb[$idx].type
|
||||
if (1 == $t)
|
||||
set $erased = $erased + 1
|
||||
else
|
||||
if (2 == $t)
|
||||
set $pending = $pending + 1
|
||||
else
|
||||
if (3 == $t)
|
||||
set $data = $data + 1
|
||||
else
|
||||
if (4 == $t)
|
||||
set $data_cur = $data_cur + 1
|
||||
else
|
||||
if (5 == $t)
|
||||
set $data_gc = $data_gc + 1
|
||||
else
|
||||
if (6 == $t)
|
||||
set $data_pending_gc = $data_pending_gc + 1
|
||||
else
|
||||
if (7 == $t)
|
||||
set $cxt = $cxt + 1
|
||||
else
|
||||
if (8 == $t)
|
||||
set $dead = $dead + 1
|
||||
else
|
||||
if (9 == $t)
|
||||
set $ebu = $ebu + 1
|
||||
else
|
||||
printf "Unknown block type: sftl.sb[%d].type = %d\n", $idx, $t
|
||||
set $unknown = $unknown + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
printf "unknown: %d\n", $unknown
|
||||
printf "erased: %d\n", $erased
|
||||
printf "erase-before-use: %d\n", $ebu
|
||||
printf "pending: %d\n", $pending
|
||||
printf "data: %d\n", $data
|
||||
printf "data_cur: %d\n", $data_cur
|
||||
printf "data_gc: %d\n", $data_gc
|
||||
printf "data_pending_gc: %d\n", $data_pending_gc
|
||||
printf "cxt: %d\n", $cxt
|
||||
printf "dead: %d\n", $dead
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
sed 's/.*://g' | awk '{ print int($1/10)*10 }' | sort -n | uniq -c
|
||||
@@ -0,0 +1,12 @@
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
|
||||
while ($idx < $max)
|
||||
set $t = sftl.sb[$idx].type
|
||||
set $v = sftl.sb[$idx].validLbas
|
||||
if ((0 == $v) && (1 != $t))
|
||||
printf "[%d]: %d\n", $idx, $t
|
||||
end
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
set $limit = 1000
|
||||
|
||||
while ($idx < $max)
|
||||
set $r = sftl.sb[$idx].reads
|
||||
if ($r >= $limit)
|
||||
printf "[%d]: %d\n", $idx, $r
|
||||
end
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
printf "Free space: %2.3f%s\n", (((float)sftl.max_lba - sftl.seaState.validLbas) * 100.0) / (float)sftl.max_lba, "%"
|
||||
@@ -0,0 +1,7 @@
|
||||
set $idx = 0
|
||||
set $max = sftl.gc.data.curZoneSize
|
||||
|
||||
while ($idx < $max)
|
||||
printf "%d: %d\n", $idx, sftl.gc.data.meta[$idx].__f1
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
@@ -0,0 +1,17 @@
|
||||
set logging redirect on
|
||||
set logging overwrite on
|
||||
set logging file ~/erases.txt
|
||||
set logging on
|
||||
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
|
||||
while ($idx < $max)
|
||||
set $t = sftl.sb[$idx].type
|
||||
set $v = sftl.sb[$idx].erases
|
||||
printf "%d:%d\n", $idx, $v
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
set logging off
|
||||
printf "Saved to ~/erases.txt; please analyze\n"
|
||||
@@ -0,0 +1,21 @@
|
||||
set logging redirect on
|
||||
set logging overwrite on
|
||||
set logging file ~/userSeq.txt
|
||||
set logging on
|
||||
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
|
||||
while ($idx < $max)
|
||||
set $t = sftl.sb[$idx].type
|
||||
set $v = 0
|
||||
if (3 == $t)
|
||||
set $v = sftl.sb[$idx].validLbas
|
||||
printf "sb:%5d erases:%5d static:%d userSeq min:%9d max:%9d avg:%9d length:%5d\n", $idx, sftl.sb[$idx].erases, (sftl.sb[$idx].num_btoc_vbas_AND_staticFlag & 1), sftl.sb_userSeq[$idx].min, sftl.sb_userSeq[$idx].max, sftl.sb_userSeq[$idx].avg, sftl.sb_userSeq[$idx].count
|
||||
|
||||
end
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
set logging off
|
||||
printf "Saved to ~/userSeq.txt; please analyze\n"
|
||||
@@ -0,0 +1,38 @@
|
||||
set logging redirect on
|
||||
set logging overwrite on
|
||||
set logging file ~/valids.txt
|
||||
set logging on
|
||||
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
set $vbas_per_sb = sftl.__geom.vbas_per_sb
|
||||
|
||||
set $bank_max = mcxt.dev.num_of_banks
|
||||
|
||||
while ($idx < $max)
|
||||
set $bank = 0
|
||||
set $base = mcxt.r_gen.bytes_per_vbn_bitmap * $idx
|
||||
|
||||
set $good = 0
|
||||
set $bad = 0
|
||||
while ($bank < $bank_max)
|
||||
if (mcxt.v2p_bitmap[$base + ($bank >> 3)] & (1 << ($bank % 8)))
|
||||
set $good = $good + 1
|
||||
else
|
||||
set $bad = $bad + 1
|
||||
end
|
||||
|
||||
set $bank = $bank + 1
|
||||
end
|
||||
|
||||
set $t = sftl.sb[$idx].type
|
||||
set $v = 0
|
||||
if (3 == $t)
|
||||
set $v = sftl.sb[$idx].validLbas
|
||||
end
|
||||
printf "%d:%d/%d,%.2f\n", $idx, $v, ($vbas_per_sb * $good) / $bank_max, (100 * ((float)$v * $bank_max) / $good / $vbas_per_sb)
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
set logging off
|
||||
printf "Saved to ~/valids.txt; please sort and graph\n"
|
||||
@@ -0,0 +1,16 @@
|
||||
set $idx = 0
|
||||
set $max = sftl.__geom.max_sb
|
||||
set $minv = 65535
|
||||
|
||||
while ($idx < $max)
|
||||
set $t = sftl.sb[$idx].type
|
||||
set $v = sftl.sb[$idx].validLbas
|
||||
if (3 == $t)
|
||||
if ($v < $minv)
|
||||
set $minv = $v
|
||||
end
|
||||
end
|
||||
set $idx = $idx + 1
|
||||
end
|
||||
|
||||
printf "Min valid: %d/%d\n", $minv, sftl.__geom.vbas_per_sb
|
||||
@@ -0,0 +1,28 @@
|
||||
set $sb = 0
|
||||
set $bank = 0
|
||||
set $sb_max = mcxt.dev.blocks_per_cau
|
||||
set $bank_max = mcxt.dev.num_of_banks
|
||||
|
||||
while ($sb < $sb_max)
|
||||
set $bank = 0
|
||||
set $base = mcxt.r_gen.bytes_per_vbn_bitmap * $sb
|
||||
|
||||
printf "sb:0x%04x |", $sb
|
||||
while ($bank < $bank_max)
|
||||
if (mcxt.v2p_bitmap[$base + ($bank >> 3)] & (1 << ($bank % 8)))
|
||||
if (mcxt.v2p_scrub_bitmap[$base + ($bank >> 3)] & (1 << ($bank % 8)))
|
||||
printf "s"
|
||||
else
|
||||
printf " "
|
||||
end
|
||||
else
|
||||
printf "x"
|
||||
end
|
||||
|
||||
set $bank = $bank + 1
|
||||
end
|
||||
printf "|\n"
|
||||
|
||||
set $sb = $sb + 1
|
||||
end
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
printf "wAmp: %.2f\n", ((float)mcxt.stat.ddwPagesWrittenCnt * sftl.__geom.vbas_per_page) / (float)sftl.stats.lbas_written
|
||||
printf "flatten wAmp: %.2f\n", ((float)sftl.stats.lbas_written + sftl.stats.lbas_flatten) / (float)sftl.stats.lbas_written
|
||||
printf "GC wAmp: %.2f\n", ((float)sftl.stats.lbas_written + sftl.stats.lbas_gc) / (float)sftl.stats.lbas_written
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
#define AND_TRACE_LAYER FTL
|
||||
|
||||
#include "s_bg.h"
|
||||
#include "s_gc.h"
|
||||
|
||||
#ifndef AND_READONLY
|
||||
|
||||
void s_bg_write(UInt32 writeSize)
|
||||
{
|
||||
s_gc_bg(writeSize);
|
||||
}
|
||||
|
||||
void s_bg_read(UInt32 readSize)
|
||||
{
|
||||
s_gc_bg(readSize);
|
||||
}
|
||||
|
||||
void s_bg_enq(UInt32 sb, BOOL32 scrubOnUECC)
|
||||
{
|
||||
s_gc_data_enq(sb, S_GC_CTX_BG);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef __S_BG_H__
|
||||
#define __S_BG_H__
|
||||
|
||||
#include "s_internal.h"
|
||||
|
||||
#ifndef AND_READONLY
|
||||
|
||||
// Called by Write
|
||||
extern void s_bg_write(UInt32 writeSize);
|
||||
extern void s_bg_read(UInt32 readSize);
|
||||
|
||||
extern void s_bg_enq(UInt32 sb, BOOL32 scrubOnUECC);
|
||||
|
||||
#endif // AND_READONLY
|
||||
|
||||
#endif // #ifndef __S_BG_H__
|
||||
|
||||
Loaded 100 of 2612 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user