stm32: Change flash IRQ priority from 2 to 6 to prevent preemption.
The flash-IRQ handler is used to flush the storage cache, ie write outstanding block data from RAM to flash. This is triggered by a timeout, or by a direct call to flush all storage caches. Prior to this commit, a timeout could trigger the cache flushing to occur during the execution of a read/write to external SPI flash storage. In such a case the storage subsystem would break down. SPI storage transfers are already protected against USB IRQs, so by changing the priority of the flash IRQ to that of the USB IRQ (what is done in this commit) the SPI transfers can be protected against any timeouts triggering a cache flush (the cache flush would be postponed until after the transfer finished, but note that in the case of SPI writes the timeout is rescheduled after the transfer finishes). The handling of internal flash sync'ing needs to be changed to directly call flash_bdev_irq_handler() sync may be called with the IRQ priority already raised (eg when called from a USB MSC IRQ handler).
This commit is contained in:
parent
6f015d337d
commit
0941a467e7
@ -143,14 +143,17 @@ int32_t flash_bdev_ioctl(uint32_t op, uint32_t arg) {
|
||||
flash_bdev_irq_handler();
|
||||
return 0;
|
||||
|
||||
case BDEV_IOCTL_SYNC:
|
||||
case BDEV_IOCTL_SYNC: {
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
if (flash_flags & FLASH_FLAG_DIRTY) {
|
||||
flash_flags |= FLASH_FLAG_FORCE_WRITE;
|
||||
while (flash_flags & FLASH_FLAG_DIRTY) {
|
||||
NVIC->STIR = FLASH_IRQn;
|
||||
flash_bdev_irq_handler();
|
||||
}
|
||||
}
|
||||
restore_irq_pri(basepri);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -MP_EINVAL;
|
||||
}
|
||||
|
@ -106,9 +106,9 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj);
|
||||
|
||||
//#def IRQ_PRI_SYSTICK 0
|
||||
#define IRQ_PRI_UART 1
|
||||
#define IRQ_PRI_FLASH 1
|
||||
#define IRQ_PRI_SDIO 1
|
||||
#define IRQ_PRI_DMA 1
|
||||
#define IRQ_PRI_FLASH 2
|
||||
#define IRQ_PRI_OTG_FS 2
|
||||
#define IRQ_PRI_OTG_HS 2
|
||||
#define IRQ_PRI_TIM5 2
|
||||
@ -126,10 +126,6 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj);
|
||||
// get dropped. The handling for each character only consumes about 0.5 usec
|
||||
#define IRQ_PRI_UART NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0)
|
||||
|
||||
// Flash IRQ must be higher priority than interrupts of all those components
|
||||
// that rely on the flash storage.
|
||||
#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 2, 0)
|
||||
|
||||
// SDIO must be higher priority than DMA for SDIO DMA transfers to work.
|
||||
#define IRQ_PRI_SDIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 4, 0)
|
||||
|
||||
@ -137,6 +133,11 @@ MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj);
|
||||
// into the sdcard driver which waits for the DMA to complete.
|
||||
#define IRQ_PRI_DMA NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 5, 0)
|
||||
|
||||
// Flash IRQ (used for flushing storage cache) must be at the same priority as
|
||||
// the USB IRQs, so that the IRQ priority can be raised to this level to disable
|
||||
// both the USB and cache flushing, when storage transfers are in progress.
|
||||
#define IRQ_PRI_FLASH NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||
|
||||
#define IRQ_PRI_OTG_FS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||
#define IRQ_PRI_OTG_HS NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||
#define IRQ_PRI_TIM5 NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 6, 0)
|
||||
|
@ -49,8 +49,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
|
||||
|
||||
case BDEV_IOCTL_SYNC:
|
||||
if (bdev->spiflash.flags & 1) {
|
||||
// we must disable USB irqs to prevent MSC contention with SPI flash
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
mp_spiflash_cache_flush(&bdev->spiflash);
|
||||
led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off
|
||||
restore_irq_pri(basepri);
|
||||
@ -61,8 +60,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
|
||||
}
|
||||
|
||||
int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
|
||||
// we must disable USB irqs to prevent MSC contention with SPI flash
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest);
|
||||
restore_irq_pri(basepri);
|
||||
|
||||
@ -70,8 +68,7 @@ int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uin
|
||||
}
|
||||
|
||||
int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
|
||||
// we must disable USB irqs to prevent MSC contention with SPI flash
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS);
|
||||
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
|
||||
int ret = mp_spiflash_cached_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src);
|
||||
if (bdev->spiflash.flags & 1) {
|
||||
led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on
|
||||
|
@ -55,8 +55,7 @@ void storage_init(void) {
|
||||
#endif
|
||||
|
||||
// Enable the flash IRQ, which is used to also call our storage IRQ handler
|
||||
// It needs to go at a higher priority than all those components that rely on
|
||||
// the flash storage (eg higher than USB MSC).
|
||||
// It must go at the same priority as USB (see comment in irq.h).
|
||||
NVIC_SetPriority(FLASH_IRQn, IRQ_PRI_FLASH);
|
||||
HAL_NVIC_EnableIRQ(FLASH_IRQn);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user