first and last commit

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

No files matched your search

@@ -0,0 +1,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