Add R/W memory and instruction barrier after mstatus access
Fast subsequent reads and writes to the mstatus csr lead to illegal instruction exceptions on the nucleisys bumblee core of the gd32vf103. This behavior only occurred in high load situations e.g. interrupt frequency of 5khz but reliably let to these errors. Adding the instruction and memory barriers solved the problem. There is some negligible performance impact.
This commit is contained in:
parent
fe3cdf8314
commit
b875108cd0
|
@ -377,7 +377,9 @@ static inline void port_init(void) {}
|
||||||
* @return The interrupts status.
|
* @return The interrupts status.
|
||||||
*/
|
*/
|
||||||
static inline syssts_t port_get_irq_status(void) {
|
static inline syssts_t port_get_irq_status(void) {
|
||||||
return (syssts_t)__RV_CSR_READ(CSR_MSTATUS);
|
syssts_t mstatus = __RV_CSR_READ(CSR_MSTATUS);
|
||||||
|
__RWMB();
|
||||||
|
return mstatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -399,7 +401,9 @@ static inline bool port_irq_enabled(syssts_t sts) { return sts & MSTATUS_MIE; }
|
||||||
* @retval true running in ISR mode.
|
* @retval true running in ISR mode.
|
||||||
*/
|
*/
|
||||||
static inline bool port_is_isr_context(void) {
|
static inline bool port_is_isr_context(void) {
|
||||||
return __RV_CSR_READ(CSR_MSUBM) & MSUBM_TYP;
|
bool is_irq_context = (__RV_CSR_READ(CSR_MSUBM) & MSUBM_TYP) != 0;
|
||||||
|
__RWMB();
|
||||||
|
return is_irq_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -407,14 +411,22 @@ static inline bool port_is_isr_context(void) {
|
||||||
* @details Usually this function just disables interrupts but may perform more
|
* @details Usually this function just disables interrupts but may perform more
|
||||||
* actions.
|
* actions.
|
||||||
*/
|
*/
|
||||||
static inline void port_lock(void) { __disable_irq(); }
|
static inline void port_lock(void) {
|
||||||
|
__disable_irq();
|
||||||
|
__RWMB();
|
||||||
|
__FENCE_I();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Kernel-unlock action.
|
* @brief Kernel-unlock action.
|
||||||
* @details Usually this function just enables interrupts but may perform more
|
* @details Usually this function just enables interrupts but may perform more
|
||||||
* actions.
|
* actions.
|
||||||
*/
|
*/
|
||||||
static inline void port_unlock(void) { __enable_irq(); }
|
static inline void port_unlock(void) {
|
||||||
|
__enable_irq();
|
||||||
|
__RWMB();
|
||||||
|
__FENCE_I();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Kernel-lock action from an interrupt handler.
|
* @brief Kernel-lock action from an interrupt handler.
|
||||||
|
@ -436,18 +448,18 @@ static inline void port_unlock_from_isr(void) { port_unlock(); }
|
||||||
* @brief Disables all the interrupt sources.
|
* @brief Disables all the interrupt sources.
|
||||||
* @note Of course non-maskable interrupt sources are not included.
|
* @note Of course non-maskable interrupt sources are not included.
|
||||||
*/
|
*/
|
||||||
static inline void port_disable(void) { __disable_irq(); }
|
static inline void port_disable(void) { port_lock(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Disables the interrupt sources below kernel-level priority.
|
* @brief Disables the interrupt sources below kernel-level priority.
|
||||||
* @note Interrupt sources above kernel level remains enabled.
|
* @note Interrupt sources above kernel level remains enabled.
|
||||||
*/
|
*/
|
||||||
static inline void port_suspend(void) { __disable_irq(); }
|
static inline void port_suspend(void) { port_lock(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables all the interrupt sources.
|
* @brief Enables all the interrupt sources.
|
||||||
*/
|
*/
|
||||||
static inline void port_enable(void) { __enable_irq(); }
|
static inline void port_enable(void) { port_unlock(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @details The function is meant to return when an interrupt becomes pending.
|
* @details The function is meant to return when an interrupt becomes pending.
|
||||||
|
|
|
@ -56,26 +56,34 @@
|
||||||
|
|
||||||
# Disable Interrupts globally.
|
# Disable Interrupts globally.
|
||||||
.macro DISABLE_MIE
|
.macro DISABLE_MIE
|
||||||
csrc CSR_MSTATUS, MSTATUS_MIE
|
csrc CSR_MSTATUS, MSTATUS_MIE
|
||||||
|
fence iorw, iorw
|
||||||
|
fence.i
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
# Enable Interrupts globally.
|
# Enable Interrupts globally.
|
||||||
.macro ENABLE_MIE
|
.macro ENABLE_MIE
|
||||||
csrs CSR_MSTATUS, MSTATUS_MIE
|
csrs CSR_MSTATUS, MSTATUS_MIE
|
||||||
|
fence iorw, iorw
|
||||||
|
fence.i
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
# Clear previous machine interrupt enable bit in mstatus (mstatus.mpie).
|
# Clear previous machine interrupt enable bit in mstatus (mstatus.mpie).
|
||||||
# On machine return (mret) mstatus.mie is assigned this value.
|
# On machine return (mret) mstatus.mie is assigned this value.
|
||||||
# Clearing this bit disables interrupts when leaving interrupt processing mode.
|
# Clearing this bit disables interrupts when leaving interrupt processing mode.
|
||||||
.macro DISABLE_MPIE
|
.macro DISABLE_MPIE
|
||||||
li a0, MSTATUS_MPIE
|
li a0, MSTATUS_MPIE
|
||||||
csrc CSR_MSTATUS, a0
|
csrc CSR_MSTATUS, a0
|
||||||
|
fence iorw, iorw
|
||||||
|
fence.i
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
# Set previous machine interrupt enable bit in mstatus (mstatus.mpie).
|
# Set previous machine interrupt enable bit in mstatus (mstatus.mpie).
|
||||||
.macro ENABLE_MPIE
|
.macro ENABLE_MPIE
|
||||||
li a0, MSTATUS_MPIE
|
li a0, MSTATUS_MPIE
|
||||||
csrs CSR_MSTATUS, a0
|
csrs CSR_MSTATUS, a0
|
||||||
|
fence iorw, iorw
|
||||||
|
fence.i
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue