summaryrefslogtreecommitdiff
path: root/platforms
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2023-11-26 22:59:38 +1100
committerGitHub <noreply@github.com>2023-11-26 22:59:38 +1100
commitf96a7bbd6304410e15fa6fc744a9b0fa660f1eeb (patch)
tree09672f15b55d62540b80cd3fa52fd0d89b6e5407 /platforms
parent3ef06aa732ce8063e11b2f983592529883f7ecbc (diff)
Cater for ECC failures in EFL wear-leveling. (#19749)
Co-authored-by: Sergey Vlasov <sigprof@gmail.com>
Diffstat (limited to 'platforms')
-rw-r--r--platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c32
-rw-r--r--platforms/chibios/interrupt_handlers.c45
-rw-r--r--platforms/chibios/platform.mk3
3 files changed, 78 insertions, 2 deletions
diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
index 3e4f5ffb89..3d6ed52e5c 100644
--- a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
+++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
@@ -17,6 +17,9 @@ static flash_sector_t first_sector = UINT16_MAX;
17static flash_sector_t sector_count = UINT16_MAX; 17static flash_sector_t sector_count = UINT16_MAX;
18static BaseFlash * flash; 18static BaseFlash * flash;
19 19
20static volatile bool is_issuing_read = false;
21static volatile bool ecc_error_occurred = false;
22
20// "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't. 23// "Automatic" detection of the flash size -- ideally ChibiOS would have this already, but alas, it doesn't.
21static inline uint32_t detect_flash_size(void) { 24static inline uint32_t detect_flash_size(void) {
22#if defined(WEAR_LEVELING_EFL_FLASH_SIZE) 25#if defined(WEAR_LEVELING_EFL_FLASH_SIZE)
@@ -131,11 +134,38 @@ bool backing_store_lock(void) {
131 return true; 134 return true;
132} 135}
133 136
137static backing_store_int_t backing_store_safe_read_from_location(backing_store_int_t *loc) {
138 backing_store_int_t value;
139 is_issuing_read = true;
140 ecc_error_occurred = false;
141 value = ~(*loc);
142 is_issuing_read = false;
143 return value;
144}
145
134bool backing_store_read(uint32_t address, backing_store_int_t *value) { 146bool backing_store_read(uint32_t address, backing_store_int_t *value) {
135 uint32_t offset = (base_offset + address); 147 uint32_t offset = (base_offset + address);
136 backing_store_int_t *loc = (backing_store_int_t *)flashGetOffsetAddress(flash, offset); 148 backing_store_int_t *loc = (backing_store_int_t *)flashGetOffsetAddress(flash, offset);
137 *value = ~(*loc); 149 backing_store_int_t tmp = backing_store_safe_read_from_location(loc);
150
151 if (ecc_error_occurred) {
152 bs_dprintf("Failed to read from backing store, ECC error detected\n");
153 ecc_error_occurred = false;
154 *value = 0;
155 return false;
156 }
157
158 *value = tmp;
159
138 bs_dprintf("Read "); 160 bs_dprintf("Read ");
139 wl_dump(offset, value, sizeof(backing_store_int_t)); 161 wl_dump(offset, value, sizeof(backing_store_int_t));
140 return true; 162 return true;
141} 163}
164
165bool backing_store_allow_ecc_errors(void) {
166 return is_issuing_read;
167}
168
169void backing_store_signal_ecc_error(void) {
170 ecc_error_occurred = true;
171}
diff --git a/platforms/chibios/interrupt_handlers.c b/platforms/chibios/interrupt_handlers.c
new file mode 100644
index 0000000000..4ba32d58e4
--- /dev/null
+++ b/platforms/chibios/interrupt_handlers.c
@@ -0,0 +1,45 @@
1// Copyright 2023 Nick Brassel (@tzarc)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4///////////////////////////////////////////////////////////////////////////////
5// BEGIN: STM32 EFL Wear-leveling ECC fault handling
6//
7// Some STM32s have ECC checks for all flash memory access. Whenever there's an
8// ECC failure, the MCU raises the NMI interrupt. Whenever we receive such an
9// interrupt whilst reading the wear-leveling EEPROM area, we gracefully cater
10// for it, signalling the wear-leveling code that a failure has occurred.
11///////////////////////////////////////////////////////////////////////////////
12
13#include <ch.h>
14#include <chcore.h>
15
16#ifdef WEAR_LEVELING_EMBEDDED_FLASH
17# ifdef QMK_MCU_SERIES_STM32L4XX
18# define ECC_ERRORS_TRIGGER_NMI_INTERRUPT
19# define ECC_CHECK_REGISTER FLASH->ECCR
20# define ECC_CHECK_FLAG FLASH_ECCR_ECCD
21# endif // QMK_MCU_SERIES_STM32L4XX
22#endif // WEAR_LEVELING_EMBEDDED_FLASH
23
24#ifdef ECC_ERRORS_TRIGGER_NMI_INTERRUPT
25
26extern bool backing_store_allow_ecc_errors(void);
27extern void backing_store_signal_ecc_error(void);
28
29void NMI_Handler(void) {
30 if ((ECC_CHECK_REGISTER) & (ECC_CHECK_FLAG)) {
31 if (backing_store_allow_ecc_errors()) {
32 (ECC_CHECK_REGISTER) = (ECC_CHECK_FLAG);
33 backing_store_signal_ecc_error();
34 return;
35 }
36 }
37
38 chSysHalt("NMI");
39}
40
41#endif // ECC_ERRORS_TRIGGER_NMI_INTERRUPT
42
43///////////////////////////////////////////////////////////////////////////////
44// END: STM32 EFL Wear-leveling ECC fault handling
45///////////////////////////////////////////////////////////////////////////////
diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk
index e42ecebdc5..f38a888012 100644
--- a/platforms/chibios/platform.mk
+++ b/platforms/chibios/platform.mk
@@ -277,7 +277,8 @@ PLATFORM_SRC = \
277 $(CHIBIOS)/os/various/syscalls.c \ 277 $(CHIBIOS)/os/various/syscalls.c \
278 $(PLATFORM_COMMON_DIR)/syscall-fallbacks.c \ 278 $(PLATFORM_COMMON_DIR)/syscall-fallbacks.c \
279 $(PLATFORM_COMMON_DIR)/wait.c \ 279 $(PLATFORM_COMMON_DIR)/wait.c \
280 $(PLATFORM_COMMON_DIR)/synchronization_util.c 280 $(PLATFORM_COMMON_DIR)/synchronization_util.c \
281 $(PLATFORM_COMMON_DIR)/interrupt_handlers.c
281 282
282# Ensure the ASM files are not subjected to LTO -- it'll strip out interrupt handlers otherwise. 283# Ensure the ASM files are not subjected to LTO -- it'll strip out interrupt handlers otherwise.
283QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM) 284QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM)