diff options
-rw-r--r-- | chip/it83xx/flash.c | 12 | ||||
-rw-r--r-- | chip/it83xx/gpio.c | 6 | ||||
-rw-r--r-- | core/nds32/atomic.h | 31 | ||||
-rw-r--r-- | core/nds32/init.S | 13 | ||||
-rw-r--r-- | core/nds32/task.c | 56 | ||||
-rw-r--r-- | include/task.h | 12 |
6 files changed, 84 insertions, 46 deletions
diff --git a/chip/it83xx/flash.c b/chip/it83xx/flash.c index 9d2f7a7c39..5155e94332 100644 --- a/chip/it83xx/flash.c +++ b/chip/it83xx/flash.c @@ -347,7 +347,6 @@ int FLASH_DMA_CODE flash_physical_read(int offset, int size, char *data) */ int FLASH_DMA_CODE flash_physical_write(int offset, int size, const char *data) { - uint32_t psw = get_psw(); if (flash_dma_code_enabled == 0) return EC_ERROR_ACCESS_DENIED; @@ -367,8 +366,7 @@ int FLASH_DMA_CODE flash_physical_write(int offset, int size, const char *data) dma_flash_aai_write(offset, size, data); dma_reset_immu(); - if (psw & PSW_GIE) - interrupt_enable(); + interrupt_enable(); return dma_flash_verify(offset, size, data); } @@ -384,7 +382,6 @@ int FLASH_DMA_CODE flash_physical_write(int offset, int size, const char *data) int FLASH_DMA_CODE flash_physical_erase(int offset, int size) { int v_size = size, v_addr = offset; - uint32_t psw = get_psw(); if (flash_dma_code_enabled == 0) return EC_ERROR_ACCESS_DENIED; @@ -406,8 +403,7 @@ int FLASH_DMA_CODE flash_physical_erase(int offset, int size) } dma_reset_immu(); - if (psw & PSW_GIE) - interrupt_enable(); + interrupt_enable(); return dma_flash_verify(v_addr, v_size, NULL); } @@ -518,7 +514,6 @@ uint32_t flash_physical_get_writable_flags(uint32_t cur_flags) static void flash_code_static_dma(void) { - uint32_t psw = get_psw(); /* Make sure no interrupt while enable static DMA */ interrupt_disable(); @@ -548,8 +543,7 @@ static void flash_code_static_dma(void) flash_dma_code_enabled = 0x01; - if (psw & PSW_GIE) - interrupt_enable(); + interrupt_enable(); } /** diff --git a/chip/it83xx/gpio.c b/chip/it83xx/gpio.c index 7ad348ce4b..f00c954f1c 100644 --- a/chip/it83xx/gpio.c +++ b/chip/it83xx/gpio.c @@ -440,9 +440,6 @@ static void __gpio_irq(void) } #endif - /* Run the GPIO master handler above with corresponding port/mask. */ - gpio_interrupt(gpio_irqs[irq].gpio_port, gpio_irqs[irq].gpio_mask); - /* * Clear the WUC status register. Note the external pin first goes * to the WUC module and is always edge triggered. @@ -454,6 +451,9 @@ static void __gpio_irq(void) * controller is level triggered from the WUC status. */ task_clear_pending_irq(irq); + + /* Run the GPIO master handler above with corresponding port/mask. */ + gpio_interrupt(gpio_irqs[irq].gpio_port, gpio_irqs[irq].gpio_mask); } /* Route all WKO interrupts coming from INT#2 into __gpio_irq. */ diff --git a/core/nds32/atomic.h b/core/nds32/atomic.h index 2b49dfe5c1..4771d31f99 100644 --- a/core/nds32/atomic.h +++ b/core/nds32/atomic.h @@ -10,47 +10,48 @@ #include "common.h" #include "cpu.h" +#include "task.h" static inline void atomic_clear(uint32_t volatile *addr, uint32_t bits) { - uint32_t psw = get_psw(); - asm volatile ("setgie.d"); + uint32_t int_mask = get_int_mask(); + interrupt_disable(); *addr &= ~bits; - set_psw(psw); + set_int_mask(int_mask); } static inline void atomic_or(uint32_t volatile *addr, uint32_t bits) { - uint32_t psw = get_psw(); - asm volatile ("setgie.d"); + uint32_t int_mask = get_int_mask(); + interrupt_disable(); *addr |= bits; - set_psw(psw); + set_int_mask(int_mask); } static inline void atomic_add(uint32_t volatile *addr, uint32_t value) { - uint32_t psw = get_psw(); - asm volatile ("setgie.d"); + uint32_t int_mask = get_int_mask(); + interrupt_disable(); *addr += value; - set_psw(psw); + set_int_mask(int_mask); } static inline void atomic_sub(uint32_t volatile *addr, uint32_t value) { - uint32_t psw = get_psw(); - asm volatile ("setgie.d"); + uint32_t int_mask = get_int_mask(); + interrupt_disable(); *addr -= value; - set_psw(psw); + set_int_mask(int_mask); } static inline uint32_t atomic_read_clear(uint32_t volatile *addr) { uint32_t val; - uint32_t psw = get_psw(); - asm volatile ("setgie.d"); + uint32_t int_mask = get_int_mask(); + interrupt_disable(); val = *addr; *addr = 0; - set_psw(psw); + set_int_mask(int_mask); return val; } #endif /* __CROS_EC_ATOMIC_H */ diff --git a/core/nds32/init.S b/core/nds32/init.S index 23483e59b0..a27fcd8d0e 100644 --- a/core/nds32/init.S +++ b/core/nds32/init.S @@ -85,6 +85,19 @@ eflash_sig: .global reset reset: + /* + * GIE (global interrupt) is always disabled here. the first + * "iret" instruction of syscall interrupt (triggered by __task_start) + * will restore PSW from IPSW, and will enable GIE. + * Firmware will not change GIE settings (set/clear) until the next + * reset, unless there's an interrupt event. + * When there is an interrupt event, N8 CPU will save PSW register to + * IPSW register and clear GIE then jump to interrupt service routine. + * N8 will restore PSW from IPSW after "iret" instruction. + */ + setgie.d + dsb + /* GP register is used to access .data and .bss */ la $gp, _SDA_BASE_ diff --git a/core/nds32/task.c b/core/nds32/task.c index baf87ffbf3..97c1ac55fb 100644 --- a/core/nds32/task.c +++ b/core/nds32/task.c @@ -152,17 +152,42 @@ static inline task_ *__task_id_to_ptr(task_id_t id) return tasks + id; } +/* + * We use INT_MASK to enable (interrupt_enable)/ + * disable (interrupt_disable) all maskable interrupts. + * And, EC modules share HW2 ~ HW15 interrupts. If corresponding + * bit of INT_MASK is set, it will never be cleared + * (see chip_disable_irq()). To enable/disable individual + * interrupt of EC module, we can use corresponding EXT_IERx registers. + * + * ------------ ----------- + * | | | ------- | + * |EC modules| | | HW2 | | + * | | | ------- | + * | INT 0 | | ------- | ------- ------- + * | ~ | --> | | HW3 | | -> | GIE | -> | CPU | + * | INT 167 | | ------- | ------- ------- + * | | | ... | | + * | | | ... | - clear by HW while + * | | | ------- | interrupt occur and + * | | | | HW15| | restore from IPSW after + * | | | ------- | instruction "iret". + * | EXT_IERx | | INT_MASK| + * ------------ ----------- + */ void interrupt_disable(void) { - /* clear GIE (Global Interrupt Enable) bit */ - asm volatile ("setgie.d"); + /* Mask all interrupts, only keep division by zero exception */ + uint32_t val = (1 << 30); + asm volatile ("mtsr %0, $INT_MASK" : : "r"(val)); asm volatile ("dsb"); } void interrupt_enable(void) { - /* set GIE (Global Interrupt Enable) bit */ - asm volatile ("setgie.e"); + /* Enable HW2 ~ HW15 and division by zero exception interrupts */ + uint32_t val = ((1 << 30) | 0xFFFC); + asm volatile ("mtsr %0, $INT_MASK" : : "r"(val)); } inline int in_interrupt_context(void) @@ -291,14 +316,14 @@ uint32_t task_wait_event(int timeout_us) return __wait_evt(timeout_us, TASK_ID_IDLE); } -static uint32_t get_int_mask(void) +uint32_t get_int_mask(void) { uint32_t ret; asm volatile ("mfsr %0, $INT_MASK" : "=r"(ret)); return ret; } -static void set_int_mask(uint32_t val) +void set_int_mask(uint32_t val) { asm volatile ("mtsr %0, $INT_MASK" : : "r"(val)); } @@ -318,16 +343,12 @@ void task_enable_all_tasks(void) void task_enable_irq(int irq) { - int cpu_int = chip_enable_irq(irq); - if (cpu_int >= 0) - set_int_mask(get_int_mask() | (1 << cpu_int)); + chip_enable_irq(irq); } void task_disable_irq(int irq) { - int cpu_int = chip_disable_irq(irq); - if (cpu_int >= 0) - set_int_mask(get_int_mask() & ~(1 << cpu_int)); + chip_disable_irq(irq); } void task_clear_pending_irq(int irq) @@ -356,9 +377,6 @@ static void ivic_init_irqs(void) /* chip-specific interrupt controller initialization */ chip_init_irqs(); - /* Mask all interrupts, only keep division by zero exception */ - set_int_mask(1 << 30 /* IDIVZ */); - /* * Re-enable global interrupts in case they're disabled. On a reboot, * they're already enabled; if we've jumped here from another image, @@ -382,24 +400,24 @@ void mutex_lock(struct mutex *mtx) ASSERT(id != TASK_ID_INVALID); /* critical section with interrupts off */ - asm volatile ("setgie.d ; dsb"); + interrupt_disable(); mtx->waiters |= id; while (1) { if (!mtx->lock) { /* we got it ! */ mtx->lock = 2; mtx->waiters &= ~id; /* end of critical section : re-enable interrupts */ - asm volatile ("setgie.e"); + interrupt_enable(); return; } else { /* Contention on the mutex */ /* end of critical section : re-enable interrupts */ - asm volatile ("setgie.e"); + interrupt_enable(); /* Sleep waiting for our turn */ /* TODO(crbug.com/435612, crbug.com/435611) * This discards any pending events! */ task_wait_event(0); /* re-enter critical section */ - asm volatile ("setgie.d ; dsb"); + interrupt_disable(); } } } diff --git a/include/task.h b/include/task.h index d7d6dd1ca3..ed635686bc 100644 --- a/include/task.h +++ b/include/task.h @@ -52,6 +52,18 @@ void interrupt_enable(void); inline int in_interrupt_context(void); /** + * Return current interrupt mask. Meaning is chip-specific and + * should not be examined; just pass it to set_int_mask() to + * restore a previous interrupt state after interrupt_disable(). + */ +uint32_t get_int_mask(void); + +/** + * Set interrupt mask. As with interrupt_disable(), use with care. + */ +void set_int_mask(uint32_t val); + +/** * Set a task event. * * If the task is higher priority than the current task, this will cause an |