wear_leveling.c (30311B)
1 // Copyright 2022 Nick Brassel (@tzarc) 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 #include <stdbool.h> 4 #include "fnv.h" 5 #include "wear_leveling.h" 6 #include "wear_leveling_drivers.h" 7 #include "wear_leveling_internal.h" 8 9 /* 10 This wear leveling algorithm is adapted from algorithms from previous 11 implementations in QMK, namely: 12 - Artur F. (http://engsta.com/stm32-flash-memory-eeprom-emulator/) 13 - Yiancar -- QMK's base implementation for STM32F303 14 - Ilya Zhuravlev -- initial wear leveling algorithm 15 - Don Kjer -- increased flash density algorithm 16 - Nick Brassel (@tzarc) -- decoupled for use on other peripherals 17 18 At this layer, it is assumed that any reads/writes from the backing store 19 have a "reset state" after erasure of zero. 20 It is up to the backing store to perform translation of values, such as 21 taking the complement in order to deal with flash memory's reset value. 22 23 Terminology: 24 25 - Backing store: this is the storage area used by the wear leveling 26 algorithm. 27 28 - Backing size: this is the amount of storage provided by the backing 29 store for use by the wear leveling algorithm. 30 31 - Backing write size: this is the minimum number of bytes the backing 32 store can write in a single operation. 33 34 - Logical data: this is the externally-visible "emulated EEPROM" that 35 external subsystems "see" when performing reads/writes. 36 37 - Logical size: this is the amount of storage available for use 38 externally. Effectively, the "size of the EEPROM". 39 40 - Write log: this is a section of the backing store used to keep track 41 of modifications without overwriting existing data. This log is 42 "played back" on startup such that any subsequent reads are capable 43 of returning the latest data. 44 45 - Consolidated data: this is a section of the backing store reserved for 46 use for the latest copy of logical data. This is only ever written 47 when the write log is full -- the latest values for the logical data 48 are written here and the write log is cleared. 49 50 Configurables: 51 52 - BACKING_STORE_WRITE_SIZE: The number of bytes requires for a write 53 operation. This is defined by the capabilities of the backing store. 54 55 - WEAR_LEVELING_BACKING_SIZE: The number of bytes provided by the 56 backing store for use by the wear leveling algorithm. This is 57 defined by the capabilities of the backing store. This value must 58 also be at least twice the size of the logical size, as well as a 59 multiple of the logical size. 60 61 - WEAR_LEVELING_LOGICAL_SIZE: The number of bytes externally visible 62 to other subsystems performing reads/writes. This must be a multiple 63 of the write size. 64 65 General algorithm: 66 67 During initialization: 68 * The contents of the consolidated data section are read into cache. 69 * The contents of the write log are "played back" and update the 70 cache accordingly. 71 72 During reads: 73 * Logical data is served from the cache. 74 75 During writes: 76 * The cache is updated with the new data. 77 * A new write log entry is appended to the log. 78 * If the log's full, data is consolidated and the write log cleared. 79 80 Write log structure: 81 82 The first 8 bytes of the write log are a FNV1a_64 hash of the contents 83 of the consolidated data area, in an attempt to detect and guard against 84 any data corruption. 85 86 The write log follows the hash: 87 88 Given that the algorithm needs to cater for 2-, 4-, and 8-byte writes, 89 a variable-length write log entry is used such that the minimal amount 90 of storage is used based off the backing store write size. 91 92 Firstly, an empty log entry is expected to be all zeros. If the backing 93 store uses 0xFF for cleared bytes, it should return the complement, such 94 that this wear-leveling algorithm "receives" zeros. 95 96 For multi-byte writes, up to 8 bytes will be used for each log entry, 97 depending on the size of backing store writes: 98 99 ╔ Multi-byte Log Entry (2, 4-byte) ═╗ 100 ║00XXXYYY║YYYYYYYY║YYYYYYYY║AAAAAAAA║ 101 ║ └┬┘└┬┘║└──┬───┘║└──┬───┘║└──┬───┘║ 102 ║ LenAdd║ Address║ Address║Value[0]║ 103 ╚════════╩════════╩════════╩════════╝ 104 ╔ Multi-byte Log Entry (2-byte) ══════════════════════╗ 105 ║00XXXYYY║YYYYYYYY║YYYYYYYY║AAAAAAAA║BBBBBBBB║CCCCCCCC║ 106 ║ └┬┘└┬┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║ 107 ║ LenAdd║ Address║ Address║Value[0]║Value[1]║Value[2]║ 108 ╚════════╩════════╩════════╩════════╩════════╩════════╝ 109 ╔ Multi-byte Log Entry (2, 4, 8-byte) ══════════════════════════════════╗ 110 ║00XXXYYY║YYYYYYYY║YYYYYYYY║AAAAAAAA║BBBBBBBB║CCCCCCCC║DDDDDDDD║EEEEEEEE║ 111 ║ └┬┘└┬┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║└──┬───┘║ 112 ║ LenAdd║ Address║ Address║Value[0]║Value[1]║Value[2]║Value[3]║Value[4]║ 113 ╚════════╩════════╩════════╩════════╩════════╩════════╩════════╩════════╝ 114 115 19 bits are used for the address, which allows for a max logical size of 116 512kB. Up to 5 bytes can be included in a single log entry. 117 118 For 2-byte backing store writes, the last two bytes are optional 119 depending on the length of data to be written. Accordingly, either 3 120 or 4 backing store write operations will occur. 121 For 4-byte backing store writes, either one or two write operations 122 occur, depending on the length. 123 For 8-byte backing store writes, one write operation occur. 124 125 2-byte backing store optimizations: 126 127 For single byte writes, addresses between 0...63 are encoded in a single 128 backing store write operation. 4- and 8-byte backing stores do not have 129 this optimization as it does not minimize the number of bytes written. 130 131 ╔ Byte-Entry ════╗ 132 ║01XXXXXXYYYYYYYY║ 133 ║ └─┬──┘└──┬───┘║ 134 ║ Address Value ║ 135 ╚════════════════╝ 136 0 <= Address < 0x40 (64) 137 138 A second optimization takes into account uint16_t writes of 0 or 1, 139 specifically catering for KC_NO and KC_TRANSPARENT in the dynamic keymap 140 subsystem. This is valid only for the first 16kB of logical data -- 141 addresses outside this range will use the multi-byte encoding above. 142 143 ╔ U16-Encoded 0 ═╗ 144 ║100XXXXXXXXXXXXX║ 145 ║ │└─────┬─────┘║ 146 ║ │Address >> 1 ║ 147 ║ └── Value: 0 ║ 148 ╚════════════════╝ 149 0 <= Address <= 0x3FFE (16382) 150 151 ╔ U16-Encoded 1 ═╗ 152 ║101XXXXXXXXXXXXX║ 153 ║ │└─────┬─────┘║ 154 ║ │Address >> 1 ║ 155 ║ └── Value: 1 ║ 156 ╚════════════════╝ 157 0 <= Address <= 0x3FFE (16382) */ 158 159 /** 160 * Storage area for the wear-leveling cache. 161 */ 162 static struct __attribute__((__aligned__(BACKING_STORE_WRITE_SIZE))) { 163 __attribute__((__aligned__(BACKING_STORE_WRITE_SIZE))) uint8_t cache[(WEAR_LEVELING_LOGICAL_SIZE)]; 164 uint32_t write_address; 165 bool unlocked; 166 } wear_leveling; 167 168 /** 169 * Locking helper: status 170 */ 171 typedef enum backing_store_lock_status_t { STATUS_FAILURE = 0, STATUS_SUCCESS, STATUS_UNCHANGED } backing_store_lock_status_t; 172 173 /** 174 * Locking helper: unlock 175 */ 176 static inline backing_store_lock_status_t wear_leveling_unlock(void) { 177 if (wear_leveling.unlocked) { 178 return STATUS_UNCHANGED; 179 } 180 if (!backing_store_unlock()) { 181 return STATUS_FAILURE; 182 } 183 wear_leveling.unlocked = true; 184 return STATUS_SUCCESS; 185 } 186 187 /** 188 * Locking helper: lock 189 */ 190 static inline backing_store_lock_status_t wear_leveling_lock(void) { 191 if (!wear_leveling.unlocked) { 192 return STATUS_UNCHANGED; 193 } 194 if (!backing_store_lock()) { 195 return STATUS_FAILURE; 196 } 197 wear_leveling.unlocked = false; 198 return STATUS_SUCCESS; 199 } 200 201 /** 202 * Resets the cache, ensuring the write address is correctly initialised. 203 */ 204 static void wear_leveling_clear_cache(void) { 205 memset(wear_leveling.cache, 0, (WEAR_LEVELING_LOGICAL_SIZE)); 206 wear_leveling.write_address = (WEAR_LEVELING_LOGICAL_SIZE) + 8; // +8 is due to the FNV1a_64 of the consolidated buffer 207 } 208 209 /** 210 * Reads the consolidated data from the backing store into the cache. 211 * Does not consider the write log. 212 */ 213 static wear_leveling_status_t wear_leveling_read_consolidated(void) { 214 wl_dprintf("Reading consolidated data\n"); 215 216 wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; 217 if (!backing_store_read_bulk(0, (backing_store_int_t *)wear_leveling.cache, sizeof(wear_leveling.cache) / sizeof(backing_store_int_t))) { 218 wl_dprintf("Failed to read from backing store\n"); 219 status = WEAR_LEVELING_FAILED; 220 } 221 222 // Verify the FNV1a_64 result 223 if (status != WEAR_LEVELING_FAILED) { 224 uint64_t expected = fnv_64a_buf(wear_leveling.cache, (WEAR_LEVELING_LOGICAL_SIZE), FNV1A_64_INIT); 225 write_log_entry_t entry; 226 wl_dprintf("Reading checksum\n"); 227 #if BACKING_STORE_WRITE_SIZE == 2 228 backing_store_read_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw16, 4); 229 #elif BACKING_STORE_WRITE_SIZE == 4 230 backing_store_read_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw32, 2); 231 #elif BACKING_STORE_WRITE_SIZE == 8 232 backing_store_read((WEAR_LEVELING_LOGICAL_SIZE) + 0, &entry.raw64); 233 #endif 234 // If we have a mismatch, clear the cache but do not flag a failure, 235 // which will cater for the completely clean MCU case. 236 if (entry.raw64 == expected) { 237 wl_dprintf("Checksum matches, consolidated data is correct\n"); 238 } else { 239 wl_dprintf("Checksum mismatch, clearing cache\n"); 240 wear_leveling_clear_cache(); 241 } 242 } 243 244 // If we failed for any reason, then clear the cache 245 if (status == WEAR_LEVELING_FAILED) { 246 wear_leveling_clear_cache(); 247 } 248 249 return status; 250 } 251 252 /** 253 * Writes the current cache to consolidated data at the beginning of the backing store. 254 * Does not clear the write log. 255 * Pre-condition: this is just after an erase, so we can write directly without reading. 256 */ 257 static wear_leveling_status_t wear_leveling_write_consolidated(void) { 258 wl_dprintf("Writing consolidated data\n"); 259 260 backing_store_lock_status_t lock_status = wear_leveling_unlock(); 261 wear_leveling_status_t status = WEAR_LEVELING_CONSOLIDATED; 262 if (!backing_store_write_bulk(0, (backing_store_int_t *)wear_leveling.cache, sizeof(wear_leveling.cache) / sizeof(backing_store_int_t))) { 263 wl_dprintf("Failed to write to backing store\n"); 264 status = WEAR_LEVELING_FAILED; 265 } 266 267 if (status != WEAR_LEVELING_FAILED) { 268 // Write out the FNV1a_64 result of the consolidated data 269 write_log_entry_t entry; 270 entry.raw64 = fnv_64a_buf(wear_leveling.cache, (WEAR_LEVELING_LOGICAL_SIZE), FNV1A_64_INIT); 271 wl_dprintf("Writing checksum\n"); 272 do { 273 #if BACKING_STORE_WRITE_SIZE == 2 274 if (!backing_store_write_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw16, 4)) { 275 status = WEAR_LEVELING_FAILED; 276 break; 277 } 278 #elif BACKING_STORE_WRITE_SIZE == 4 279 if (!backing_store_write_bulk((WEAR_LEVELING_LOGICAL_SIZE), entry.raw32, 2)) { 280 status = WEAR_LEVELING_FAILED; 281 break; 282 } 283 #elif BACKING_STORE_WRITE_SIZE == 8 284 if (!backing_store_write((WEAR_LEVELING_LOGICAL_SIZE), entry.raw64)) { 285 status = WEAR_LEVELING_FAILED; 286 break; 287 } 288 #endif 289 } while (0); 290 } 291 292 if (lock_status == STATUS_SUCCESS) { 293 wear_leveling_lock(); 294 } 295 return status; 296 } 297 298 /** 299 * Forces a write of the current cache. 300 * Erases the backing store, including the write log. 301 * During this operation, there is the potential for data loss if a power loss occurs. 302 */ 303 static wear_leveling_status_t wear_leveling_consolidate_force(void) { 304 wl_dprintf("Erasing backing store\n"); 305 306 // Erase the backing store. Expectation is that any un-written values that are read back after this call come back as zero. 307 bool ok = backing_store_erase(); 308 if (!ok) { 309 wl_dprintf("Failed to erase backing store\n"); 310 return WEAR_LEVELING_FAILED; 311 } 312 313 // Write the cache to the first section of the backing store. 314 wear_leveling_status_t status = wear_leveling_write_consolidated(); 315 if (status == WEAR_LEVELING_FAILED) { 316 wl_dprintf("Failed to write consolidated data\n"); 317 } 318 319 // Next write of the log occurs after the consolidated values at the start of the backing store. 320 wear_leveling.write_address = (WEAR_LEVELING_LOGICAL_SIZE) + 8; // +8 due to the FNV1a_64 of the consolidated area 321 322 return status; 323 } 324 325 /** 326 * Potential write of the current cache to the backing store. 327 * Skipped if the current write log position is not at the end of the backing store. 328 * During this operation, there is the potential for data loss if a power loss occurs. 329 * 330 * @return true if consolidation occurred 331 */ 332 static wear_leveling_status_t wear_leveling_consolidate_if_needed(void) { 333 if (wear_leveling.write_address >= (WEAR_LEVELING_BACKING_SIZE)) { 334 return wear_leveling_consolidate_force(); 335 } 336 337 return WEAR_LEVELING_SUCCESS; 338 } 339 340 /** 341 * Appends the supplied fixed-width entry to the write log, optionally consolidating if the log is full. 342 * 343 * @return true if consolidation occurred 344 */ 345 static wear_leveling_status_t wear_leveling_append_raw(backing_store_int_t value) { 346 bool ok = backing_store_write(wear_leveling.write_address, value); 347 if (!ok) { 348 wl_dprintf("Failed to write to backing store\n"); 349 return WEAR_LEVELING_FAILED; 350 } 351 wear_leveling.write_address += (BACKING_STORE_WRITE_SIZE); 352 return wear_leveling_consolidate_if_needed(); 353 } 354 355 /** 356 * Handles writing multi_byte-encoded data to the backing store. 357 * 358 * @return true if consolidation occurred 359 */ 360 static wear_leveling_status_t wear_leveling_write_raw_multibyte(uint32_t address, const void *value, size_t length) { 361 const uint8_t *p = value; 362 write_log_entry_t log = LOG_ENTRY_MAKE_MULTIBYTE(address, length); 363 for (size_t i = 0; i < length; ++i) { 364 log.raw8[3 + i] = p[i]; 365 } 366 367 // Write to the backing store. See the multi-byte log format in the documentation header at the top of the file. 368 wear_leveling_status_t status; 369 #if BACKING_STORE_WRITE_SIZE == 2 370 status = wear_leveling_append_raw(log.raw16[0]); 371 if (status != WEAR_LEVELING_SUCCESS) { 372 return status; 373 } 374 375 status = wear_leveling_append_raw(log.raw16[1]); 376 if (status != WEAR_LEVELING_SUCCESS) { 377 return status; 378 } 379 380 if (length > 1) { 381 status = wear_leveling_append_raw(log.raw16[2]); 382 if (status != WEAR_LEVELING_SUCCESS) { 383 return status; 384 } 385 } 386 387 if (length > 3) { 388 status = wear_leveling_append_raw(log.raw16[3]); 389 if (status != WEAR_LEVELING_SUCCESS) { 390 return status; 391 } 392 } 393 #elif BACKING_STORE_WRITE_SIZE == 4 394 status = wear_leveling_append_raw(log.raw32[0]); 395 if (status != WEAR_LEVELING_SUCCESS) { 396 return status; 397 } 398 399 if (length > 1) { 400 status = wear_leveling_append_raw(log.raw32[1]); 401 if (status != WEAR_LEVELING_SUCCESS) { 402 return status; 403 } 404 } 405 #elif BACKING_STORE_WRITE_SIZE == 8 406 status = wear_leveling_append_raw(log.raw64); 407 if (status != WEAR_LEVELING_SUCCESS) { 408 return status; 409 } 410 #endif 411 return status; 412 } 413 414 /** 415 * Handles the actual writing of logical data into the write log section of the backing store. 416 */ 417 static wear_leveling_status_t wear_leveling_write_raw(uint32_t address, const void *value, size_t length) { 418 const uint8_t *p = value; 419 size_t remaining = length; 420 wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; 421 while (remaining > 0) { 422 #if BACKING_STORE_WRITE_SIZE == 2 423 // Small-write optimizations - uint16_t, 0 or 1, address is even, address <16384: 424 if (remaining >= 2 && address % 2 == 0 && address < 16384) { 425 const uint16_t v = ((uint16_t)p[1]) << 8 | p[0]; // don't just dereference a uint16_t here -- if unaligned it generates faults on some MCUs 426 if (v == 0 || v == 1) { 427 const write_log_entry_t log = LOG_ENTRY_MAKE_WORD_01(address, v); 428 status = wear_leveling_append_raw(log.raw16[0]); 429 if (status != WEAR_LEVELING_SUCCESS) { 430 // If consolidation occurred, then the cache has already been written to the consolidated area. No need to continue. 431 // If a failure occurred, pass it on. 432 return status; 433 } 434 435 remaining -= 2; 436 address += 2; 437 p += 2; 438 continue; 439 } 440 } 441 442 // Small-write optimizations - address<64: 443 if (address < 64) { 444 const write_log_entry_t log = LOG_ENTRY_MAKE_OPTIMIZED_64(address, *p); 445 status = wear_leveling_append_raw(log.raw16[0]); 446 if (status != WEAR_LEVELING_SUCCESS) { 447 // If consolidation occurred, then the cache has already been written to the consolidated area. No need to continue. 448 // If a failure occurred, pass it on. 449 return status; 450 } 451 452 remaining--; 453 address++; 454 p++; 455 continue; 456 } 457 #endif // BACKING_STORE_WRITE_SIZE == 2 458 const size_t this_length = remaining >= LOG_ENTRY_MULTIBYTE_MAX_BYTES ? LOG_ENTRY_MULTIBYTE_MAX_BYTES : remaining; 459 status = wear_leveling_write_raw_multibyte(address, p, this_length); 460 if (status != WEAR_LEVELING_SUCCESS) { 461 // If consolidation occurred, then the cache has already been written to the consolidated area. No need to continue. 462 // If a failure occurred, pass it on. 463 return status; 464 } 465 remaining -= this_length; 466 address += (uint32_t)this_length; 467 p += this_length; 468 } 469 470 return status; 471 } 472 473 /** 474 * "Replays" the write log from the backing store, updating the local cache with updated values. 475 */ 476 static wear_leveling_status_t wear_leveling_playback_log(void) { 477 wl_dprintf("Playback write log\n"); 478 479 wear_leveling_status_t status = WEAR_LEVELING_SUCCESS; 480 bool cancel_playback = false; 481 uint32_t address = (WEAR_LEVELING_LOGICAL_SIZE) + 8; // +8 due to the FNV1a_64 of the consolidated area 482 while (!cancel_playback && address < (WEAR_LEVELING_BACKING_SIZE)) { 483 backing_store_int_t value; 484 bool ok = backing_store_read(address, &value); 485 if (!ok) { 486 wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); 487 cancel_playback = true; 488 status = WEAR_LEVELING_FAILED; 489 break; 490 } 491 if (value == 0) { 492 wl_dprintf("Found empty slot, no more log entries\n"); 493 cancel_playback = true; 494 break; 495 } 496 497 // If we got a nonzero value, then we need to increment the address to ensure next write occurs at next location 498 address += (BACKING_STORE_WRITE_SIZE); 499 500 // Read from the write log 501 write_log_entry_t log; 502 #if BACKING_STORE_WRITE_SIZE == 2 503 log.raw16[0] = value; 504 #elif BACKING_STORE_WRITE_SIZE == 4 505 log.raw32[0] = value; 506 #elif BACKING_STORE_WRITE_SIZE == 8 507 log.raw64 = value; 508 #endif 509 510 switch (LOG_ENTRY_GET_TYPE(log)) { 511 case LOG_ENTRY_TYPE_MULTIBYTE: { 512 #if BACKING_STORE_WRITE_SIZE == 2 513 ok = backing_store_read(address, &log.raw16[1]); 514 if (!ok) { 515 wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); 516 cancel_playback = true; 517 status = WEAR_LEVELING_FAILED; 518 break; 519 } 520 address += (BACKING_STORE_WRITE_SIZE); 521 #endif // BACKING_STORE_WRITE_SIZE == 2 522 const uint32_t a = LOG_ENTRY_MULTIBYTE_GET_ADDRESS(log); 523 const uint8_t l = LOG_ENTRY_MULTIBYTE_GET_LENGTH(log); 524 525 if (a + l > (WEAR_LEVELING_LOGICAL_SIZE)) { 526 cancel_playback = true; 527 status = WEAR_LEVELING_FAILED; 528 break; 529 } 530 531 #if BACKING_STORE_WRITE_SIZE == 2 532 if (l > 1) { 533 ok = backing_store_read(address, &log.raw16[2]); 534 if (!ok) { 535 wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); 536 cancel_playback = true; 537 status = WEAR_LEVELING_FAILED; 538 break; 539 } 540 address += (BACKING_STORE_WRITE_SIZE); 541 } 542 if (l > 3) { 543 ok = backing_store_read(address, &log.raw16[3]); 544 if (!ok) { 545 wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); 546 cancel_playback = true; 547 status = WEAR_LEVELING_FAILED; 548 break; 549 } 550 address += (BACKING_STORE_WRITE_SIZE); 551 } 552 #elif BACKING_STORE_WRITE_SIZE == 4 553 if (l > 1) { 554 ok = backing_store_read(address, &log.raw32[1]); 555 if (!ok) { 556 wl_dprintf("Failed to load from backing store, skipping playback of write log\n"); 557 cancel_playback = true; 558 status = WEAR_LEVELING_FAILED; 559 break; 560 } 561 address += (BACKING_STORE_WRITE_SIZE); 562 } 563 #endif 564 565 memcpy(&wear_leveling.cache[a], &log.raw8[3], l); 566 } break; 567 #if BACKING_STORE_WRITE_SIZE == 2 568 case LOG_ENTRY_TYPE_OPTIMIZED_64: { 569 const uint32_t a = LOG_ENTRY_OPTIMIZED_64_GET_ADDRESS(log); 570 const uint8_t v = LOG_ENTRY_OPTIMIZED_64_GET_VALUE(log); 571 572 if (a >= (WEAR_LEVELING_LOGICAL_SIZE)) { 573 cancel_playback = true; 574 status = WEAR_LEVELING_FAILED; 575 break; 576 } 577 578 wear_leveling.cache[a] = v; 579 } break; 580 case LOG_ENTRY_TYPE_WORD_01: { 581 const uint32_t a = LOG_ENTRY_WORD_01_GET_ADDRESS(log); 582 const uint8_t v = LOG_ENTRY_WORD_01_GET_VALUE(log); 583 584 if (a + 1 >= (WEAR_LEVELING_LOGICAL_SIZE)) { 585 cancel_playback = true; 586 status = WEAR_LEVELING_FAILED; 587 break; 588 } 589 590 wear_leveling.cache[a + 0] = v; 591 wear_leveling.cache[a + 1] = 0; 592 } break; 593 #endif // BACKING_STORE_WRITE_SIZE == 2 594 default: { 595 cancel_playback = true; 596 status = WEAR_LEVELING_FAILED; 597 } break; 598 } 599 } 600 601 // We've reached the end of the log, so we're at the new write location 602 wear_leveling.write_address = address; 603 604 if (status == WEAR_LEVELING_FAILED) { 605 // If we had a failure during readback, assume we're corrupted -- force a consolidation with the data we already have 606 status = wear_leveling_consolidate_force(); 607 } else { 608 // Consolidate the cache + write log if required 609 status = wear_leveling_consolidate_if_needed(); 610 } 611 612 return status; 613 } 614 615 /** 616 * Wear-leveling initialization 617 */ 618 wear_leveling_status_t wear_leveling_init(void) { 619 wl_dprintf("Init\n"); 620 621 // Reset the cache 622 wear_leveling_clear_cache(); 623 624 // Initialise the backing store 625 if (!backing_store_init()) { 626 // If it failed, clear the cache and return with failure 627 wear_leveling_clear_cache(); 628 return WEAR_LEVELING_FAILED; 629 } 630 631 // Read the previous consolidated values, then replay the existing write log so that the cache has the "live" values 632 wear_leveling_status_t status = wear_leveling_read_consolidated(); 633 if (status == WEAR_LEVELING_FAILED) { 634 // If it failed, clear the cache and return with failure 635 wear_leveling_clear_cache(); 636 return status; 637 } 638 639 status = wear_leveling_playback_log(); 640 if (status == WEAR_LEVELING_FAILED) { 641 // If it failed, clear the cache and return with failure 642 wear_leveling_clear_cache(); 643 return status; 644 } 645 646 return status; 647 } 648 649 /** 650 * Wear-leveling erase. 651 * Post-condition: any reads from the backing store directly after an erase operation must come back as zero. 652 */ 653 wear_leveling_status_t wear_leveling_erase(void) { 654 wl_dprintf("Erase\n"); 655 656 // Unlock the backing store 657 backing_store_lock_status_t lock_status = wear_leveling_unlock(); 658 if (lock_status == STATUS_FAILURE) { 659 wear_leveling_lock(); 660 return WEAR_LEVELING_FAILED; 661 } 662 663 // Perform the erase 664 bool ret = backing_store_erase(); 665 wear_leveling_clear_cache(); 666 667 // Lock the backing store if we acquired the lock successfully 668 if (lock_status == STATUS_SUCCESS) { 669 ret &= (wear_leveling_lock() != STATUS_FAILURE); 670 } 671 672 return ret ? WEAR_LEVELING_SUCCESS : WEAR_LEVELING_FAILED; 673 } 674 675 /** 676 * Writes logical data into the backing store. Skips writes if there are no changes to values. 677 */ 678 wear_leveling_status_t wear_leveling_write(const uint32_t address, const void *value, size_t length) { 679 wl_assert(address + length <= (WEAR_LEVELING_LOGICAL_SIZE)); 680 if (address + length > (WEAR_LEVELING_LOGICAL_SIZE)) { 681 return WEAR_LEVELING_FAILED; 682 } 683 684 wl_dprintf("Write "); 685 wl_dump(address, value, length); 686 687 // Skip write if there's no change compared to the current cached value 688 if (memcmp(value, &wear_leveling.cache[address], length) == 0) { 689 return true; 690 } 691 692 // Update the cache before writing to the backing store -- if we hit the end of the backing store during writes to the log then we'll force a consolidation in-line 693 memcpy(&wear_leveling.cache[address], value, length); 694 695 // Unlock the backing store 696 backing_store_lock_status_t lock_status = wear_leveling_unlock(); 697 if (lock_status == STATUS_FAILURE) { 698 wear_leveling_lock(); 699 return WEAR_LEVELING_FAILED; 700 } 701 702 // Perform the actual write 703 wear_leveling_status_t status = wear_leveling_write_raw(address, value, length); 704 switch (status) { 705 case WEAR_LEVELING_CONSOLIDATED: 706 case WEAR_LEVELING_FAILED: 707 // If the write triggered consolidation, or the write failed, then nothing else needs to occur. 708 break; 709 710 case WEAR_LEVELING_SUCCESS: 711 // Consolidate the cache + write log if required 712 status = wear_leveling_consolidate_if_needed(); 713 break; 714 715 default: 716 // Unsure how we'd get here... 717 status = WEAR_LEVELING_FAILED; 718 break; 719 } 720 721 if (lock_status == STATUS_SUCCESS) { 722 if (wear_leveling_lock() == STATUS_FAILURE) { 723 status = WEAR_LEVELING_FAILED; 724 } 725 } 726 727 return status; 728 } 729 730 /** 731 * Reads logical data from the cache. 732 */ 733 wear_leveling_status_t wear_leveling_read(const uint32_t address, void *value, size_t length) { 734 wl_assert(address + length <= (WEAR_LEVELING_LOGICAL_SIZE)); 735 if (address + length > (WEAR_LEVELING_LOGICAL_SIZE)) { 736 return WEAR_LEVELING_FAILED; 737 } 738 739 // Only need to copy from the cache 740 memcpy(value, &wear_leveling.cache[address], length); 741 742 wl_dprintf("Read "); 743 wl_dump(address, value, length); 744 return WEAR_LEVELING_SUCCESS; 745 } 746 747 /** 748 * Weak implementation of bulk read, drivers can implement more optimised implementations. 749 */ 750 __attribute__((weak)) bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { 751 for (size_t i = 0; i < item_count; ++i) { 752 if (!backing_store_read(address + (i * BACKING_STORE_WRITE_SIZE), &values[i])) { 753 return false; 754 } 755 } 756 return true; 757 } 758 759 /** 760 * Weak implementation of bulk write, drivers can implement more optimised implementations. 761 */ 762 __attribute__((weak)) bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) { 763 for (size_t i = 0; i < item_count; ++i) { 764 if (!backing_store_write(address + (i * BACKING_STORE_WRITE_SIZE), values[i])) { 765 return false; 766 } 767 } 768 return true; 769 }