rp2/rp2_flash: Lockout second core only when doing flash erase/write.
Using the multicore lockout feature in the general atomic section makes it much more difficult to get correct. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
9feb0689ee
commit
4b4f6011e8
|
@ -52,9 +52,6 @@ uint32_t mp_thread_begin_atomic_section(void) {
|
||||||
// When both cores are executing, we also need to provide
|
// When both cores are executing, we also need to provide
|
||||||
// full mutual exclusion.
|
// full mutual exclusion.
|
||||||
mp_thread_mutex_lock(&atomic_mutex, 1);
|
mp_thread_mutex_lock(&atomic_mutex, 1);
|
||||||
// In case this atomic section is for flash access, then
|
|
||||||
// suspend the other core.
|
|
||||||
multicore_lockout_start_blocking();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return save_and_disable_interrupts();
|
return save_and_disable_interrupts();
|
||||||
|
@ -64,7 +61,6 @@ void mp_thread_end_atomic_section(uint32_t state) {
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
if (core1_entry) {
|
if (core1_entry) {
|
||||||
multicore_lockout_end_blocking();
|
|
||||||
mp_thread_mutex_unlock(&atomic_mutex);
|
mp_thread_mutex_unlock(&atomic_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,22 @@ bi_decl(bi_block_device(
|
||||||
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
|
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
|
||||||
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
|
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
|
||||||
|
|
||||||
|
// Flash erase and write must run with interrupts disabled and the other core suspended,
|
||||||
|
// because the XIP bit gets disabled.
|
||||||
|
static uint32_t begin_critical_flash_section(void) {
|
||||||
|
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
|
||||||
|
multicore_lockout_start_blocking();
|
||||||
|
}
|
||||||
|
return save_and_disable_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_critical_flash_section(uint32_t state) {
|
||||||
|
restore_interrupts(state);
|
||||||
|
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
|
||||||
|
multicore_lockout_end_blocking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t rp2_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
STATIC mp_obj_t rp2_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
enum { ARG_start, ARG_len };
|
enum { ARG_start, ARG_len };
|
||||||
|
@ -135,19 +151,17 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
||||||
if (n_args == 3) {
|
if (n_args == 3) {
|
||||||
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
|
mp_uint_t atomic_state = begin_critical_flash_section();
|
||||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
|
||||||
flash_range_erase(self->flash_base + offset, bufinfo.len);
|
flash_range_erase(self->flash_base + offset, bufinfo.len);
|
||||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
end_critical_flash_section(atomic_state);
|
||||||
mp_event_handle_nowait();
|
mp_event_handle_nowait();
|
||||||
// TODO check return value
|
// TODO check return value
|
||||||
} else {
|
} else {
|
||||||
offset += mp_obj_get_int(args[3]);
|
offset += mp_obj_get_int(args[3]);
|
||||||
}
|
}
|
||||||
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
|
mp_uint_t atomic_state = begin_critical_flash_section();
|
||||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
|
||||||
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
|
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
|
||||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
end_critical_flash_section(atomic_state);
|
||||||
mp_event_handle_nowait();
|
mp_event_handle_nowait();
|
||||||
// TODO check return value
|
// TODO check return value
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
|
@ -170,10 +184,9 @@ STATIC mp_obj_t rp2_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
|
||||||
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
|
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
|
||||||
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
|
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
|
||||||
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
|
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
|
||||||
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
|
mp_uint_t atomic_state = begin_critical_flash_section();
|
||||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
|
||||||
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
|
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
|
||||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
end_critical_flash_section(atomic_state);
|
||||||
// TODO check return value
|
// TODO check return value
|
||||||
return MP_OBJ_NEW_SMALL_INT(0);
|
return MP_OBJ_NEW_SMALL_INT(0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue