From 92999681e3344b551ad10c8ddff9afd47864e2c6 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sat, 11 May 2019 01:21:13 +0900 Subject: [PATCH 1/2] Add flash partitioning system --- src/main/cli/cli.c | 16 +++-- src/main/cms/cms_menu_blackbox.c | 6 +- src/main/drivers/flash.c | 103 ++++++++++++++++++++++++++++++- src/main/drivers/flash.h | 30 ++++++++- src/main/drivers/flash_w25n01g.c | 24 ++++--- src/main/fc/init.c | 6 +- src/main/io/flashfs.c | 71 +++++++++++---------- src/main/msp/msp.c | 8 ++- src/main/osd/osd.c | 7 ++- 9 files changed, 215 insertions(+), 56 deletions(-) diff --git a/src/main/cli/cli.c b/src/main/cli/cli.c index b45dc05970..4d8fe20704 100644 --- a/src/main/cli/cli.c +++ b/src/main/cli/cli.c @@ -2209,16 +2209,24 @@ static void cliSdInfo(char *cmdline) #endif -#ifdef USE_FLASHFS +#ifdef USE_FLASH_CHIP static void cliFlashInfo(char *cmdline) { - const flashGeometry_t *layout = flashfsGetGeometry(); + const flashGeometry_t *layout = flashGetGeometry(); UNUSED(cmdline); - cliPrintLinef("Flash sectors=%u, sectorSize=%u, pagesPerSector=%u, pageSize=%u, totalSize=%u, usedSize=%u", - layout->sectors, layout->sectorSize, layout->pagesPerSector, layout->pageSize, layout->totalSize, flashfsGetOffset()); + cliPrintLinef("Flash sectors=%u, sectorSize=%u, pagesPerSector=%u, pageSize=%u, totalSize=%u", + layout->sectors, layout->sectorSize, layout->pagesPerSector, layout->pageSize, layout->totalSize); +#ifdef USE_FLASHFS + const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + + cliPrintLinef("FlashFS size=%u, usedSize=%u", + FLASH_PARTITION_SECTOR_COUNT(flashPartition) * layout->sectorSize, + flashfsGetOffset() + ); +#endif } diff --git a/src/main/cms/cms_menu_blackbox.c b/src/main/cms/cms_menu_blackbox.c index 2e80875706..39f4a2de3d 100644 --- a/src/main/cms/cms_menu_blackbox.c +++ b/src/main/cms/cms_menu_blackbox.c @@ -126,9 +126,11 @@ static void cmsx_Blackbox_GetDeviceStatus(void) if (storageDeviceIsWorking) { tfp_sprintf(cmsx_BlackboxStatus, "READY"); - const flashGeometry_t *geometry = flashfsGetGeometry(); + const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + const flashGeometry_t *flashGeometry = flashGetGeometry(); + storageUsed = flashfsGetOffset() / 1024; - storageFree = (geometry->totalSize / 1024) - storageUsed; + storageFree = ((FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize) / 1024) - storageUsed; } else { tfp_sprintf(cmsx_BlackboxStatus, "FAULT"); } diff --git a/src/main/drivers/flash.c b/src/main/drivers/flash.c index 8cc40557b6..232d1189d8 100644 --- a/src/main/drivers/flash.c +++ b/src/main/drivers/flash.c @@ -20,6 +20,7 @@ #include #include +#include #include "platform.h" @@ -41,6 +42,9 @@ static busDevice_t busInstance; static busDevice_t *busdev; static flashDevice_t flashDevice; +static flashPartitionTable_t flashPartitionTable; + +static void flashConfigurePartitions(void); #define FLASH_INSTRUCTION_RDID 0x9F @@ -177,7 +181,7 @@ static bool flashSpiInit(const flashConfig_t *flashConfig) } #endif // USE_SPI -bool flashInit(const flashConfig_t *flashConfig) +bool flashDeviceInit(const flashConfig_t *flashConfig) { #ifdef USE_SPI bool useSpi = (SPI_CFG_TO_DEV(flashConfig->spiDevice) != SPIINVALID); @@ -197,6 +201,17 @@ bool flashInit(const flashConfig_t *flashConfig) return false; } +bool flashInit(const flashConfig_t *flashConfig) +{ + memset(&flashPartitionTable, 0x00, sizeof(flashPartitionTable)); + + bool haveFlash = flashDeviceInit(flashConfig); + + flashConfigurePartitions(); + + return haveFlash; +} + bool flashIsReady(void) { return flashDevice.vTable->isReady(&flashDevice); @@ -259,4 +274,90 @@ const flashGeometry_t *flashGetGeometry(void) return &noFlashGeometry; } + +/* + * Flash partitioning + * + * Partition table is not currently stored on the flash, in-memory only. + * + * Partitions are required so that Badblock management (inc spare blocks), FlashFS (Blackbox Logging), Configuration and Firmware can be kept separate and tracked. + * + * Currently, to keep things simple (and working), the following rules apply: + * + * 1) order of partitions in the paritions table strictly defined as follows + * + * BAD BLOCK MANAGEMENT + * FIRMWARE + * FLASH FS + * + * 2) If firmware or bootloader doesn't use or care about a particular type partition the corresponding entry should be empty, i.e. partition table entry memset to 0x00. + * + * 3) flash FS must start at sector 0. IMPORTANT: There is existing blackbox/flash FS code the relies on this!!! + */ +static void flashConfigurePartitions(void) +{ + + const flashGeometry_t *flashGeometry = flashGetGeometry(); + if (flashGeometry->totalSize == 0) { + return; + } + + flashSector_t startSector = 0; + flashSector_t endSector = flashGeometry->sectors - 1; // 0 based index + + const flashPartition_t *badBlockPartition = flashFindPartitionByUsage(FLASH_PARTITION_BADBLOCK_MANAGEMENT); + if (badBlockPartition) { + endSector = badBlockPartition->startSector - 1; + } + +#if defined(FIRMWARE_SIZE) + const uint32_t firmwareSize = (FIRMWARE_SIZE * 1024); + flashSector_t firmwareSectors = (firmwareSize / flashGeometry->sectorSize); + + if (firmwareSize % flashGeometry->sectorSize > 0) { + firmwareSectors++; // needs a portion of a sector. + } + + startSector = (endSector + 1) - firmwareSectors; // + 1 for inclusive + + const flashPartition_t firmwarePartition = { + .usage = FLASH_PARTITION_FIRMWARE, + .startSector = startSector, + .endSector = endSector + }; + + endSector = startSector - 1; + startSector = 0; + + flashSetPartition(1, &firmwarePartition); +#endif + +#ifdef USE_FLASHFS + const flashPartition_t flashFsPartition = { + .usage = FLASH_PARTITION_FLASHFS, + .startSector = startSector, + .endSector = endSector + }; + + flashSetPartition(2, &flashFsPartition); +#endif +} + +void flashSetPartition(uint8_t index, const flashPartition_t *partition) +{ + memcpy(&flashPartitionTable.partitions[index], partition, sizeof(*partition)); +} + +const flashPartition_t *flashFindPartitionByUsage(uint8_t usage) +{ + for (int index = 0; index < FLASH_MAX_PARTITIONS; index++) { + flashPartition_t *candidate = &flashPartitionTable.partitions[index]; + if (candidate->usage == usage) { + return candidate; + } + } + + return NULL; +} + #endif // USE_FLASH_CHIP diff --git a/src/main/drivers/flash.h b/src/main/drivers/flash.h index d811e77f1e..1ccd869cc4 100644 --- a/src/main/drivers/flash.h +++ b/src/main/drivers/flash.h @@ -36,8 +36,10 @@ typedef enum { FLASH_TYPE_NAND } flashType_e; +typedef uint16_t flashSector_t; + typedef struct flashGeometry_s { - uint16_t sectors; // Count of the number of erasable blocks on the device + flashSector_t sectors; // Count of the number of erasable blocks on the device uint16_t pageSize; // In bytes uint32_t sectorSize; // This is just pagesPerSector * pageSize uint32_t totalSize; // This is just sectorSize * sectors @@ -59,3 +61,29 @@ void flashPageProgram(uint32_t address, const uint8_t *data, int length); int flashReadBytes(uint32_t address, uint8_t *buffer, int length); void flashFlush(void); const flashGeometry_t *flashGetGeometry(void); + +// +// flash partitioning api +// + +typedef struct flashPartition_s { + uint8_t usage; + flashSector_t startSector; + flashSector_t endSector; +} flashPartition_t; + +#define FLASH_PARTITION_SECTOR_COUNT(partition) (partition->endSector + 1 - partition->startSector) // + 1 for inclusive, start and end sector can be the same sector. + +#define FLASH_PARTITION_UNKNOWN 0 +#define FLASH_PARTITION_FLASHFS 1 +#define FLASH_PARTITION_BADBLOCK_MANAGEMENT 2 +#define FLASH_PARTITION_FIRMWARE 3 + +#define FLASH_MAX_PARTITIONS 3 + +typedef struct flashPartitionTable_s { + flashPartition_t partitions[FLASH_MAX_PARTITIONS]; +} flashPartitionTable_t; + +void flashSetPartition(uint8_t index, const flashPartition_t *partition); +const flashPartition_t *flashFindPartitionByUsage(uint8_t usage); diff --git a/src/main/drivers/flash_w25n01g.c b/src/main/drivers/flash_w25n01g.c index 5d22d9e490..f65c6965b4 100644 --- a/src/main/drivers/flash_w25n01g.c +++ b/src/main/drivers/flash_w25n01g.c @@ -58,6 +58,15 @@ serialPort_t *debugSerialPort = NULL; #define W25N01G_PAGES_PER_BLOCK 64 #define W25N01G_BLOCKS_PER_DIE 1024 +// BB replacement area +#define W25N01G_BB_MARKER_BLOCKS 1 +#define W25N01G_BB_REPLACEMENT_BLOCKS 20 +#define W25N01G_BB_MANAGEMENT_BLOCKS (W25N01G_BB_REPLACEMENT_BLOCKS + W25N01G_BB_MARKER_BLOCKS) +// blocks are zero-based index +#define W25N01G_BB_REPLACEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_REPLACEMENT_BLOCKS) +#define W25N01G_BB_MANAGEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_MANAGEMENT_BLOCKS) +#define W25N01G_BB_MARKER_BLOCK (W25N01G_BB_REPLACEMENT_START_BLOCK - W25N01G_BB_MARKER_BLOCKS) + // Instructions #define W25N01G_INSTRUCTION_RDID 0x9F @@ -113,12 +122,6 @@ serialPort_t *debugSerialPort = NULL; #define W25N01G_BLOCK_TO_PAGE(block) ((block) * W25N01G_PAGES_PER_BLOCK) #define W25N01G_BLOCK_TO_LINEAR(block) (W25N01G_BLOCK_TO_PAGE(block) * W25N01G_PAGE_SIZE) -// BB replacement area -#define W25N01G_BB_MARKER_BLOCKS 1 -#define W25N01G_BB_REPLACEMENT_BLOCKS 21 -#define W25N01G_BB_REPLACEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_REPLACEMENT_BLOCKS) -#define W25N01G_BB_MARKER_BLOCK (W25N01G_BB_REPLACEMENT_START_BLOCK - W25N01G_BB_MARKER_BLOCKS) - // The timeout values (2ms minimum to avoid 1 tick advance in consecutive calls to millis). #define W25N01G_TIMEOUT_PAGE_READ_MS 2 // tREmax = 60us (ECC enabled) #define W25N01G_TIMEOUT_PAGE_PROGRAM_MS 2 // tPPmax = 700us @@ -322,6 +325,12 @@ static void w25n01g_writeEnable(flashDevice_t *fdevice) */ const flashVTable_t w25n01g_vTable; +static const flashPartition_t badBlockPartition = { + .usage = FLASH_PARTITION_BADBLOCK_MANAGEMENT, + .startSector = W25N01G_BB_MANAGEMENT_START_BLOCK, + .endSector = W25N01G_BB_MANAGEMENT_START_BLOCK + W25N01G_BB_MANAGEMENT_BLOCKS - 1 // -1 for inclusive, 0 based. +}; + static void w25n01g_deviceInit(flashDevice_t *flashdev); bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID) @@ -354,10 +363,11 @@ bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID) } fdevice->geometry.flashType = FLASH_TYPE_NAND; - fdevice->geometry.sectors -= W25N01G_BB_REPLACEMENT_BLOCKS; fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize; fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors; + flashSetPartition(0, &badBlockPartition); + fdevice->couldBeBusy = true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be w25n01g_deviceReset(fdevice); diff --git a/src/main/fc/init.c b/src/main/fc/init.c index e24807b176..969034892c 100644 --- a/src/main/fc/init.c +++ b/src/main/fc/init.c @@ -716,11 +716,9 @@ void init(void) #endif #ifdef USE_FLASH_CHIP - bool haveFlash = flashInit(flashConfig()); + flashInit(flashConfig()); #ifdef USE_FLASHFS - if (haveFlash) { - flashfsInit(); - } + flashfsInit(); #endif #endif diff --git a/src/main/io/flashfs.c b/src/main/io/flashfs.c index 15ae0e51b4..11d58b0917 100644 --- a/src/main/io/flashfs.c +++ b/src/main/io/flashfs.c @@ -43,6 +43,10 @@ #include "io/flashfs.h" +static const flashPartition_t *flashPartition = NULL; +static const flashGeometry_t *flashGeometry = NULL; +static uint32_t flashfsSize = 0; + static uint8_t flashWriteBuffer[FLASHFS_WRITE_BUFFER_SIZE]; /* The position of our head and tail in the circular flash write buffer. @@ -74,7 +78,10 @@ static void flashfsSetTailAddress(uint32_t address) void flashfsEraseCompletely(void) { - flashEraseCompletely(); + for (flashSector_t sectorIndex = flashPartition->startSector; sectorIndex <= flashPartition->endSector; sectorIndex++) { + uint32_t sectorAddress = sectorIndex * flashGeometry->sectorSize; + flashEraseSector(sectorAddress); + } flashfsClearBuffer(); @@ -87,24 +94,23 @@ void flashfsEraseCompletely(void) */ void flashfsEraseRange(uint32_t start, uint32_t end) { - const flashGeometry_t *geometry = flashGetGeometry(); - - if (geometry->sectorSize <= 0) + if (flashGeometry->sectorSize <= 0) return; // Round the start down to a sector boundary - int startSector = start / geometry->sectorSize; + int startSector = start / flashGeometry->sectorSize; // And the end upward - int endSector = end / geometry->sectorSize; - int endRemainder = end % geometry->sectorSize; + int endSector = end / flashGeometry->sectorSize; + int endRemainder = end % flashGeometry->sectorSize; if (endRemainder > 0) { endSector++; } - for (int i = startSector; i < endSector; i++) { - flashEraseSector(i * geometry->sectorSize); + for (int sectorIndex = startSector; sectorIndex < endSector; sectorIndex++) { + uint32_t sectorAddress = sectorIndex * flashGeometry->sectorSize; + flashEraseSector(sectorAddress); } } @@ -120,12 +126,12 @@ bool flashfsIsReady(void) bool flashfsIsSupported(void) { - return flashfsGetSize() > 0; + return flashfsSize > 0; } uint32_t flashfsGetSize(void) { - return flashGetGeometry()->totalSize; + return flashfsSize; } static uint32_t flashfsTransmitBufferUsed(void) @@ -152,11 +158,6 @@ uint32_t flashfsGetWriteBufferFreeSpace(void) return flashfsGetWriteBufferSize() - flashfsTransmitBufferUsed(); } -const flashGeometry_t* flashfsGetGeometry(void) -{ - return flashGetGeometry(); -} - /** * Write the given buffers to flash sequentially at the current tail address, advancing the tail address after * each write. @@ -192,7 +193,7 @@ static uint32_t flashfsWriteBuffers(uint8_t const **buffers, uint32_t *bufferSiz uint32_t bytesTotalRemaining = bytesTotal; - uint16_t pageSize = flashfsGetGeometry()->pageSize; + uint16_t pageSize = flashGeometry->pageSize; while (bytesTotalRemaining > 0) { uint32_t bytesTotalThisIteration; @@ -482,9 +483,9 @@ int flashfsReadAbs(uint32_t address, uint8_t *buffer, unsigned int len) int bytesRead; // Did caller try to read past the end of the volume? - if (address + len > flashfsGetSize()) { + if (address + len > flashfsSize) { // Truncate their request - len = flashfsGetSize() - address; + len = flashfsSize - address; } // Since the read could overlap data in our dirty buffers, force a sync to clear those first @@ -528,7 +529,7 @@ int flashfsIdentifyStartOfFreeSpace(void) } testBuffer; int left = 0; // Smallest block index in the search region - int right = flashfsGetSize() / FREE_BLOCK_SIZE; // One past the largest block index in the search region + int right = flashfsSize / FREE_BLOCK_SIZE; // One past the largest block index in the search region int mid; int result = right; int i; @@ -571,12 +572,12 @@ int flashfsIdentifyStartOfFreeSpace(void) */ bool flashfsIsEOF(void) { - return tailAddress >= flashfsGetSize(); + return tailAddress >= flashfsSize; } void flashfsClose(void) { - switch(flashfsGetGeometry()->flashType) { + switch(flashGeometry->flashType) { case FLASH_TYPE_NOR: break; @@ -584,7 +585,7 @@ void flashfsClose(void) flashFlush(); // Advance tailAddress to next page boundary. - uint32_t pageSize = flashfsGetGeometry()->pageSize; + uint32_t pageSize = flashGeometry->pageSize; flashfsSetTailAddress((tailAddress + pageSize - 1) & ~(pageSize - 1)); break; @@ -594,30 +595,36 @@ void flashfsClose(void) /** * Call after initializing the flash chip in order to set up the filesystem. */ -void flashfsInit(void) +void flashfsInit() { - // If we have a flash chip present at all - if (flashfsGetSize() > 0) { - // Start the file pointer off at the beginning of free space so caller can start writing immediately - flashfsSeekAbs(flashfsIdentifyStartOfFreeSpace()); + flashfsSize = 0; + + flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + flashGeometry = flashGetGeometry(); + + if (!flashPartition) { + return; } + + flashfsSize = FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize; + + // Start the file pointer off at the beginning of free space so caller can start writing immediately + flashfsSeekAbs(flashfsIdentifyStartOfFreeSpace()); } #ifdef USE_FLASH_TOOLS bool flashfsVerifyEntireFlash(void) { - flashEraseCompletely(); + flashfsEraseCompletely(); flashfsInit(); - const flashGeometry_t *flashGeometry = flashfsGetGeometry(); - uint32_t address = 0; flashfsSeekAbs(address); const int bufferSize = 32; char buffer[bufferSize + 1]; - const uint32_t testLimit = flashGeometry->totalSize; + const uint32_t testLimit = flashfsGetSize(); for (address = 0; address < testLimit; address += bufferSize) { tfp_sprintf(buffer, "%08x >> **0123456789ABCDEF**", address); diff --git a/src/main/msp/msp.c b/src/main/msp/msp.c index 25e7db5ac4..35b4c1464c 100644 --- a/src/main/msp/msp.c +++ b/src/main/msp/msp.c @@ -337,10 +337,12 @@ static void serializeDataflashSummaryReply(sbuf_t *dst) if (flashfsIsSupported()) { uint8_t flags = MSP_FLASHFS_FLAG_SUPPORTED; flags |= (flashfsIsReady() ? MSP_FLASHFS_FLAG_READY : 0); - const flashGeometry_t *geometry = flashfsGetGeometry(); + + const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + sbufWriteU8(dst, flags); - sbufWriteU32(dst, geometry->sectors); - sbufWriteU32(dst, geometry->totalSize); + sbufWriteU32(dst, FLASH_PARTITION_SECTOR_COUNT(flashPartition)); + sbufWriteU32(dst, flashfsGetSize()); sbufWriteU32(dst, flashfsGetOffset()); // Effectively the current number of bytes stored on the volume } else #endif diff --git a/src/main/osd/osd.c b/src/main/osd/osd.c index a37024aeb0..0d28f7d2b8 100644 --- a/src/main/osd/osd.c +++ b/src/main/osd/osd.c @@ -432,8 +432,11 @@ static void osdGetBlackboxStatusString(char * buff) #ifdef USE_FLASHFS case BLACKBOX_DEVICE_FLASH: if (storageDeviceIsWorking) { - const flashGeometry_t *geometry = flashfsGetGeometry(); - storageTotal = geometry->totalSize / 1024; + + const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + const flashGeometry_t *flashGeometry = flashGetGeometry(); + + storageTotal = ((FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize) / 1024); storageUsed = flashfsGetOffset() / 1024; } break; From f5084a59bd6e2ff288fec0ae3b0adf6c63e2c893 Mon Sep 17 00:00:00 2001 From: jflyper Date: Sun, 19 May 2019 18:42:39 +0900 Subject: [PATCH 2/2] Partitions are now accessed by types rather than indices --- src/main/cli/cli.c | 14 +++- src/main/cms/cms_menu_blackbox.c | 2 +- src/main/drivers/flash.c | 125 ++++++++++++++++++++----------- src/main/drivers/flash.h | 25 ++++--- src/main/drivers/flash_w25n01g.c | 10 +-- src/main/io/flashfs.c | 4 +- src/main/msp/msp.c | 2 +- src/main/osd/osd.c | 2 +- 8 files changed, 117 insertions(+), 67 deletions(-) diff --git a/src/main/cli/cli.c b/src/main/cli/cli.c index 4d8fe20704..ddc832602e 100644 --- a/src/main/cli/cli.c +++ b/src/main/cli/cli.c @@ -2219,8 +2219,20 @@ static void cliFlashInfo(char *cmdline) cliPrintLinef("Flash sectors=%u, sectorSize=%u, pagesPerSector=%u, pageSize=%u, totalSize=%u", layout->sectors, layout->sectorSize, layout->pagesPerSector, layout->pageSize, layout->totalSize); + + for (uint8_t index = 0; index < FLASH_MAX_PARTITIONS; index++) { + const flashPartition_t *partition; + if (index == 0) { + cliPrintLine("Paritions:"); + } + partition = flashPartitionFindByIndex(index); + if (!partition) { + break; + } + cliPrintLinef(" %d: %s %u %u", index, flashPartitionGetTypeName(partition->type), partition->startSector, partition->endSector); + } #ifdef USE_FLASHFS - const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS); cliPrintLinef("FlashFS size=%u, usedSize=%u", FLASH_PARTITION_SECTOR_COUNT(flashPartition) * layout->sectorSize, diff --git a/src/main/cms/cms_menu_blackbox.c b/src/main/cms/cms_menu_blackbox.c index 39f4a2de3d..18b4a72a73 100644 --- a/src/main/cms/cms_menu_blackbox.c +++ b/src/main/cms/cms_menu_blackbox.c @@ -126,7 +126,7 @@ static void cmsx_Blackbox_GetDeviceStatus(void) if (storageDeviceIsWorking) { tfp_sprintf(cmsx_BlackboxStatus, "READY"); - const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS); const flashGeometry_t *flashGeometry = flashGetGeometry(); storageUsed = flashfsGetOffset() / 1024; diff --git a/src/main/drivers/flash.c b/src/main/drivers/flash.c index 232d1189d8..1e16a370e1 100644 --- a/src/main/drivers/flash.c +++ b/src/main/drivers/flash.c @@ -43,8 +43,7 @@ static busDevice_t *busdev; static flashDevice_t flashDevice; static flashPartitionTable_t flashPartitionTable; - -static void flashConfigurePartitions(void); +static int flashPartitions = 0; #define FLASH_INSTRUCTION_RDID 0x9F @@ -201,17 +200,6 @@ bool flashDeviceInit(const flashConfig_t *flashConfig) return false; } -bool flashInit(const flashConfig_t *flashConfig) -{ - memset(&flashPartitionTable, 0x00, sizeof(flashPartitionTable)); - - bool haveFlash = flashDeviceInit(flashConfig); - - flashConfigurePartitions(); - - return haveFlash; -} - bool flashIsReady(void) { return flashDevice.vTable->isReady(&flashDevice); @@ -282,18 +270,12 @@ const flashGeometry_t *flashGetGeometry(void) * * Partitions are required so that Badblock management (inc spare blocks), FlashFS (Blackbox Logging), Configuration and Firmware can be kept separate and tracked. * - * Currently, to keep things simple (and working), the following rules apply: - * - * 1) order of partitions in the paritions table strictly defined as follows - * - * BAD BLOCK MANAGEMENT - * FIRMWARE - * FLASH FS - * - * 2) If firmware or bootloader doesn't use or care about a particular type partition the corresponding entry should be empty, i.e. partition table entry memset to 0x00. - * - * 3) flash FS must start at sector 0. IMPORTANT: There is existing blackbox/flash FS code the relies on this!!! + * XXX FIXME + * XXX Note that Flash FS must start at sector 0. + * XXX There is existing blackbox/flash FS code the relies on this!!! + * XXX This restriction can and will be fixed by creating a set of flash operation functions that take partition as an additional parameter. */ + static void flashConfigurePartitions(void) { @@ -305,7 +287,7 @@ static void flashConfigurePartitions(void) flashSector_t startSector = 0; flashSector_t endSector = flashGeometry->sectors - 1; // 0 based index - const flashPartition_t *badBlockPartition = flashFindPartitionByUsage(FLASH_PARTITION_BADBLOCK_MANAGEMENT); + const flashPartition_t *badBlockPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT); if (badBlockPartition) { endSector = badBlockPartition->startSector - 1; } @@ -320,39 +302,38 @@ static void flashConfigurePartitions(void) startSector = (endSector + 1) - firmwareSectors; // + 1 for inclusive - const flashPartition_t firmwarePartition = { - .usage = FLASH_PARTITION_FIRMWARE, - .startSector = startSector, - .endSector = endSector - }; + flashPartitionSet(FLASH_PARTITION_TYPE_FIRMWARE, startSector, endSector); endSector = startSector - 1; startSector = 0; +#endif - flashSetPartition(1, &firmwarePartition); +#if defined(EEPROM_IN_EXTERNAL_FLASH) + const uint32_t configSize = EEPROM_SIZE; + flashSector_t configSectors = (configSize / flashGeometry->sectorSize); + + if (configSize % flashGeometry->sectorSize > 0) { + configSectors++; // needs a portion of a sector. + } + + startSector = (endSector + 1) - configSectors; // + 1 for inclusive + + flashPartitionSet(FLASH_PARTITION_TYPE_CONFIG, startSector, endSector); + + endSector = startSector - 1; + startSector = 0; #endif #ifdef USE_FLASHFS - const flashPartition_t flashFsPartition = { - .usage = FLASH_PARTITION_FLASHFS, - .startSector = startSector, - .endSector = endSector - }; - - flashSetPartition(2, &flashFsPartition); + flashPartitionSet(FLASH_PARTITION_TYPE_FLASHFS, startSector, endSector); #endif } -void flashSetPartition(uint8_t index, const flashPartition_t *partition) -{ - memcpy(&flashPartitionTable.partitions[index], partition, sizeof(*partition)); -} - -const flashPartition_t *flashFindPartitionByUsage(uint8_t usage) +flashPartition_t *flashPartitionFindByType(uint8_t type) { for (int index = 0; index < FLASH_MAX_PARTITIONS; index++) { flashPartition_t *candidate = &flashPartitionTable.partitions[index]; - if (candidate->usage == usage) { + if (candidate->type == type) { return candidate; } } @@ -360,4 +341,58 @@ const flashPartition_t *flashFindPartitionByUsage(uint8_t usage) return NULL; } +const flashPartition_t *flashPartitionFindByIndex(uint8_t index) +{ + if (index >= flashPartitions) { + return NULL; + } + + return &flashPartitionTable.partitions[index]; +} + +void flashPartitionSet(uint8_t type, uint32_t startSector, uint32_t endSector) +{ + flashPartition_t *entry = flashPartitionFindByType(type); + + if (!entry) { + if (flashPartitions == FLASH_MAX_PARTITIONS - 1) { + return; + } + entry = &flashPartitionTable.partitions[flashPartitions++]; + } + + entry->type = type; + entry->startSector = startSector; + entry->endSector = endSector; +} + +// Must be in sync with FLASH_PARTITION_TYPE +static const char *flashPartitionNames[] = { + "UNKNOWN ", + "PARTITION", + "FLASHFS ", + "BBMGMT ", + "FIRMWARE ", + "CONFIG ", +}; + +const char *flashPartitionGetTypeName(flashPartitionType_e type) +{ + if (type < ARRAYLEN(flashPartitionNames)) { + return flashPartitionNames[type]; + } + + return NULL; +} + +bool flashInit(const flashConfig_t *flashConfig) +{ + memset(&flashPartitionTable, 0x00, sizeof(flashPartitionTable)); + + bool haveFlash = flashDeviceInit(flashConfig); + + flashConfigurePartitions(); + + return haveFlash; +} #endif // USE_FLASH_CHIP diff --git a/src/main/drivers/flash.h b/src/main/drivers/flash.h index 1ccd869cc4..330674372e 100644 --- a/src/main/drivers/flash.h +++ b/src/main/drivers/flash.h @@ -67,23 +67,30 @@ const flashGeometry_t *flashGetGeometry(void); // typedef struct flashPartition_s { - uint8_t usage; + uint8_t type; flashSector_t startSector; flashSector_t endSector; } flashPartition_t; #define FLASH_PARTITION_SECTOR_COUNT(partition) (partition->endSector + 1 - partition->startSector) // + 1 for inclusive, start and end sector can be the same sector. -#define FLASH_PARTITION_UNKNOWN 0 -#define FLASH_PARTITION_FLASHFS 1 -#define FLASH_PARTITION_BADBLOCK_MANAGEMENT 2 -#define FLASH_PARTITION_FIRMWARE 3 - -#define FLASH_MAX_PARTITIONS 3 +// Must be in sync with flashPartitionTypeNames[] +// Should not be deleted or reordered once the code is writing a table to a flash. +typedef enum { + FLASH_PARTITION_TYPE_UNKNOWN = 0, + FLASH_PARTITION_TYPE_PARTITION_TABLE, + FLASH_PARTITION_TYPE_FLASHFS, + FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT, + FLASH_PARTITION_TYPE_FIRMWARE, + FLASH_PARTITION_TYPE_CONFIG, + FLASH_MAX_PARTITIONS +} flashPartitionType_e; typedef struct flashPartitionTable_s { flashPartition_t partitions[FLASH_MAX_PARTITIONS]; } flashPartitionTable_t; -void flashSetPartition(uint8_t index, const flashPartition_t *partition); -const flashPartition_t *flashFindPartitionByUsage(uint8_t usage); +void flashPartitionSet(uint8_t index, uint32_t startSector, uint32_t endSector); +flashPartition_t *flashPartitionFindByType(flashPartitionType_e type); +const flashPartition_t *flashPartitionFindByIndex(uint8_t index); +const char *flashPartitionGetTypeName(flashPartitionType_e type); diff --git a/src/main/drivers/flash_w25n01g.c b/src/main/drivers/flash_w25n01g.c index f65c6965b4..0cb3f287af 100644 --- a/src/main/drivers/flash_w25n01g.c +++ b/src/main/drivers/flash_w25n01g.c @@ -325,12 +325,6 @@ static void w25n01g_writeEnable(flashDevice_t *fdevice) */ const flashVTable_t w25n01g_vTable; -static const flashPartition_t badBlockPartition = { - .usage = FLASH_PARTITION_BADBLOCK_MANAGEMENT, - .startSector = W25N01G_BB_MANAGEMENT_START_BLOCK, - .endSector = W25N01G_BB_MANAGEMENT_START_BLOCK + W25N01G_BB_MANAGEMENT_BLOCKS - 1 // -1 for inclusive, 0 based. -}; - static void w25n01g_deviceInit(flashDevice_t *flashdev); bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID) @@ -366,7 +360,9 @@ bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID) fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize; fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors; - flashSetPartition(0, &badBlockPartition); + flashPartitionSet(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT, + W25N01G_BB_MANAGEMENT_START_BLOCK, + W25N01G_BB_MANAGEMENT_START_BLOCK + W25N01G_BB_MANAGEMENT_BLOCKS - 1); fdevice->couldBeBusy = true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be diff --git a/src/main/io/flashfs.c b/src/main/io/flashfs.c index 11d58b0917..6c0e1a6f72 100644 --- a/src/main/io/flashfs.c +++ b/src/main/io/flashfs.c @@ -595,11 +595,11 @@ void flashfsClose(void) /** * Call after initializing the flash chip in order to set up the filesystem. */ -void flashfsInit() +void flashfsInit(void) { flashfsSize = 0; - flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS); flashGeometry = flashGetGeometry(); if (!flashPartition) { diff --git a/src/main/msp/msp.c b/src/main/msp/msp.c index 35b4c1464c..0bc9c2b247 100644 --- a/src/main/msp/msp.c +++ b/src/main/msp/msp.c @@ -338,7 +338,7 @@ static void serializeDataflashSummaryReply(sbuf_t *dst) uint8_t flags = MSP_FLASHFS_FLAG_SUPPORTED; flags |= (flashfsIsReady() ? MSP_FLASHFS_FLAG_READY : 0); - const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS); sbufWriteU8(dst, flags); sbufWriteU32(dst, FLASH_PARTITION_SECTOR_COUNT(flashPartition)); diff --git a/src/main/osd/osd.c b/src/main/osd/osd.c index 0d28f7d2b8..ee881f42c5 100644 --- a/src/main/osd/osd.c +++ b/src/main/osd/osd.c @@ -433,7 +433,7 @@ static void osdGetBlackboxStatusString(char * buff) case BLACKBOX_DEVICE_FLASH: if (storageDeviceIsWorking) { - const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS); + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS); const flashGeometry_t *flashGeometry = flashGetGeometry(); storageTotal = ((FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize) / 1024);