qmsi: flash: Improved reentrancy of the soc flash driver

Calls to flash write or erase operations can get preempted
in the middle of the API call if a concurrent call (from
other fiber or task) to the same API is made. The patch ensures
concurrent API calls from other fiber/task is put on hold until
the current operation is completed.

The mechanism is by default not activated. To enable
it, the following flag needs to be defined:

CONFIG_SOC_FLASH_QMSI_API_REENTRANCY

Jira: ZEP-414

Change-Id: I39429e40cb6ed446123dd1a1d7c7acc1b12417aa
Signed-off-by: Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
This commit is contained in:
Kuo-Lang Tseng 2016-05-27 16:09:22 -07:00 committed by Andrew Boie
commit 2f4975b625
2 changed files with 66 additions and 1 deletions

View file

@ -131,3 +131,11 @@ config SOC_FLASH_NRF5_DEV_NAME
default "NRF5_FLASH" default "NRF5_FLASH"
help help
Specify the device name for the flash driver. Specify the device name for the flash driver.
config SOC_FLASH_QMSI_API_REENTRANCY
bool
prompt "flash driver API reentrancy for QMSI shim driver"
depends on SOC_FLASH_QMSI
default n
help
Enable support for QMSI flash driver API reentrancy.

View file

@ -25,6 +25,54 @@
#include "qm_flash.h" #include "qm_flash.h"
#include "qm_soc_regs.h" #include "qm_soc_regs.h"
struct soc_flash_data {
struct nano_sem sem;
};
#ifdef CONFIG_SOC_FLASH_QMSI_API_REENTRANCY
static struct soc_flash_data soc_flash_context;
#define FLASH_CONTEXT (&soc_flash_context)
static const int reentrancy_protection = 1;
#else
#define FLASH_CONTEXT (NULL)
static const int reentrancy_protection;
#endif /* CONFIG_SOC_FLASH_QMSI_API_REENTRANCY */
static void flash_reentrancy_init(struct device *dev)
{
struct soc_flash_data *context = dev->driver_data;
if (!reentrancy_protection) {
return;
}
nano_sem_init(&context->sem);
nano_sem_give(&context->sem);
}
static void flash_critical_region_start(struct device *dev)
{
struct soc_flash_data *context = dev->driver_data;
if (!reentrancy_protection) {
return;
}
nano_sem_take(&context->sem, TICKS_UNLIMITED);
}
static void flash_critical_region_end(struct device *dev)
{
struct soc_flash_data *context = dev->driver_data;
if (!reentrancy_protection) {
return;
}
nano_sem_give(&context->sem);
}
static inline bool is_aligned_32(uint32_t data) static inline bool is_aligned_32(uint32_t data)
{ {
return (data & 0x3) ? false : true; return (data & 0x3) ? false : true;
@ -136,7 +184,9 @@ static int flash_qmsi_write(struct device *dev, off_t addr,
} }
#endif #endif
flash_critical_region_start(dev);
qm_flash_word_write(flash, reg, offset, data_word); qm_flash_word_write(flash, reg, offset, data_word);
flash_critical_region_end(dev);
} }
return 0; return 0;
@ -178,7 +228,9 @@ static int flash_qmsi_erase(struct device *dev, off_t addr, size_t size)
(QM_FLASH_PAGE_SIZE_BITS + 1)); (QM_FLASH_PAGE_SIZE_BITS + 1));
} }
#endif #endif
flash_critical_region_start(dev);
qm_flash_page_erase(flash, reg, page); qm_flash_page_erase(flash, reg, page);
flash_critical_region_end(dev);
} }
return 0; return 0;
@ -197,12 +249,15 @@ static int flash_qmsi_write_protection(struct device *dev, bool enable)
qm_cfg.write_disable = QM_FLASH_WRITE_ENABLE; qm_cfg.write_disable = QM_FLASH_WRITE_ENABLE;
} }
flash_critical_region_start(dev);
qm_flash_set_config(QM_FLASH_0, &qm_cfg); qm_flash_set_config(QM_FLASH_0, &qm_cfg);
#if defined(CONFIG_SOC_QUARK_SE) #if defined(CONFIG_SOC_QUARK_SE)
qm_flash_set_config(QM_FLASH_1, &qm_cfg); qm_flash_set_config(QM_FLASH_1, &qm_cfg);
#endif #endif
flash_critical_region_end(dev);
return 0; return 0;
} }
@ -229,9 +284,11 @@ static int quark_flash_init(struct device *dev)
qm_flash_set_config(QM_FLASH_1, &qm_cfg); qm_flash_set_config(QM_FLASH_1, &qm_cfg);
#endif #endif
flash_reentrancy_init(dev);
return 0; return 0;
} }
DEVICE_INIT(quark_flash, CONFIG_SOC_FLASH_QMSI_DEV_NAME, DEVICE_INIT(quark_flash, CONFIG_SOC_FLASH_QMSI_DEV_NAME,
quark_flash_init, NULL, NULL, SECONDARY, quark_flash_init, FLASH_CONTEXT, NULL, SECONDARY,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE); CONFIG_KERNEL_INIT_PRIORITY_DEVICE);