123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- /* ------------------------------------------
- * Copyright (c) 2016, Synopsys, Inc. All rights reserved.
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1) Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * 2) Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * \version 2016.05
- * \date 2014-07-15
- * \author Wayne Ren(Wei.Ren@synopsys.com)
- --------------------------------------------- */
- /**
- * \file
- * \ingroup ARC_HAL_EXCEPTION_CPU ARC_HAL_EXCEPTION_INTERRUPT
- * \brief C Implementation of exception and interrupt management
- */
- #include "inc/arc/arc_exception.h"
- #include "inc/arc/arc_cache.h"
- //#define DBG_LESS
- //#include "embARC_debug.h"
- /**
- * \addtogroup ARC_HAL_EXCEPTION_CPU
- * @{
- * \var exc_entry_table
- * \brief exception entry table
- *
- * install exception entry table to ARC_AUX_INT_VECT_BASE in startup.
- * According to ARCv2 ISA, vectors are fetched in instruction space and thus
- * may be present in ICCM, Instruction Cache, or
- * main memory accessed by instruction fetch logic.
- * So it is put into a specific section .vector.
- *
- * Please note that the exc_entry_table maybe cached in ARC. Some functions is
- * defined in .s files.
- *
- */
- /**
- * \ingroup ARC_HAL_EXCEPTION_CPU
- * \brief default cpu exception handler
- * \param p_excinf pointer to the exception frame
- */
- static void exc_handler_default(void *p_excinf)
- {
- // uint32_t excpt_cause_reg = 0;
- // uint32_t excpt_ret_reg = 0;
- // uint32_t exc_no = 0;
- // excpt_cause_reg = _arc_aux_read(AUX_ECR);
- // excpt_ret_reg = _arc_aux_read(AUX_ERRET);
- // exc_no = (excpt_cause_reg >> 16) & 0xff;
- Asm("kflag 1");
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_INTERRUPT
- * \brief default interrupt handler
- * \param[in] p_excinf information for interrupt handler
- */
- static void int_handler_default(void *p_excinf)
- {
- // uint32_t int_cause_reg = 0;
- // int_cause_reg = _arc_aux_read(AUX_IRQ_CAUSE);
- Asm("kflag 1");
- }
- __attribute__ ((aligned(1024), section(".vector")))
- EXC_ENTRY exc_entry_table[NUM_EXC_ALL] = {
- [0] = _arc_reset,
- [1 ... NUM_EXC_CPU-1] = exc_entry_cpu,
- [NUM_EXC_CPU ... NUM_EXC_ALL-1] = exc_entry_int
- };
- /**
- * \var exc_int_handler_table
- * \brief the cpu exception and interrupt exception handler table
- * called in exc_entry_default and exc_entry_int
- */
- EXC_HANDLER exc_int_handler_table[NUM_EXC_ALL] = {
- [0 ... NUM_EXC_CPU-1] = exc_handler_default,
- [NUM_EXC_CPU ... NUM_EXC_ALL-1] = int_handler_default
- };
- /**
- * \var exc_nest_count
- * \brief the counter for exc/int processing, =0 no int/exc
- * >1 in int/exc processing
- * @}
- */
- uint32_t exc_nest_count;
- typedef struct aux_irq_ctrl_field {
- /* note: little endian */
- uint32_t save_nr_gpr_pairs: 5; /** Indicates number of general-purpose register pairs saved, from 0 to 8/16 */
- uint32_t res: 4; /** Reserved */
- uint32_t save_blink: 1; /** Indicates whether to save and restore BLINK */
- uint32_t save_lp_regs: 1; /** Indicates whether to save and restore loop registers (LP_COUNT, LP_START, LP_END) */
- uint32_t save_u_to_u: 1; /** Indicates if user context is saved to user stack */
- uint32_t res2: 1; /** Reserved */
- uint32_t save_idx_regs: 1; /** Indicates whether to save and restore code-density registers (EI_BASE, JLI_BASE, LDI_BASE) */
- uint32_t res3: 18; /** Reserved */
- } aux_irq_ctrl_field_t;
- typedef union {
- aux_irq_ctrl_field_t bits;
- uint32_t value;
- } aux_irq_ctrl_t;
- /**
- * \ingroup ARC_HAL_EXCEPTION_CPU ARC_HAL_EXCEPTION_INTERRUPT
- * \brief intialize the exception and interrupt handling
- */
- void exc_int_init(void)
- {
- uint32_t i;
- uint32_t status;
- aux_irq_ctrl_t ictrl;
- ictrl.value = 0;
- #ifndef ARC_FEATURE_RF16
- ictrl.bits.save_nr_gpr_pairs = 6; /* r0 to r11 (r12 saved manually) */
- #else
- ictrl.bits.save_nr_gpr_pairs = 3; /* r0 to r3, r10, r11 */
- #endif
- ictrl.bits.save_blink = 1;
- ictrl.bits.save_lp_regs = 1; /* LP_COUNT, LP_START, LP_END */
- ictrl.bits.save_u_to_u = 0; /* user ctxt saved on kernel stack */
- ictrl.bits.save_idx_regs = 1; /* JLI, LDI, EI */
- status = arc_lock_save();
- for (i = NUM_EXC_CPU; i < NUM_EXC_ALL; i++) {
- /* interrupt level triggered, disabled, priority is the lowest */
- _arc_aux_write(AUX_IRQ_SELECT, i);
- _arc_aux_write(AUX_IRQ_ENABLE, 0);
- _arc_aux_write(AUX_IRQ_TRIGGER, 0);
- #if defined(ARC_FEATURE_SEC_PRESENT) && (SECURESHIELD_VERSION < 2)
- _arc_aux_write(AUX_IRQ_PRIORITY, (1 << AUX_IRQ_PRIORITY_BIT_S)|(INT_PRI_MAX - INT_PRI_MIN));
- #else
- _arc_aux_write(AUX_IRQ_PRIORITY, INT_PRI_MAX - INT_PRI_MIN);
- #endif
- }
- _arc_aux_write(AUX_IRQ_CTRL, ictrl.value);
- arc_unlock_restore(status);
- /** ipm should be set after cpu unlock restore to avoid reset of the status32 value */
- arc_int_ipm_set((INT_PRI_MAX - INT_PRI_MIN));
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_CPU
- * \brief install a CPU exception entry
- * \param[in] excno exception number
- * \param[in] entry the entry of exception to install
- */
- int32_t exc_entry_install(const uint32_t excno, EXC_ENTRY entry)
- {
- uint32_t status;
- EXC_ENTRY *table = (EXC_ENTRY *)_arc_aux_read(AUX_INT_VECT_BASE);
- if (excno < NUM_EXC_ALL && entry != NULL
- && table[excno] != entry) {
- status = cpu_lock_save();
- /* directly write to mem, as arc gets exception handler from mem not from cache */
- /* FIXME, here maybe icache is dirty, need to be invalidated */
- table[excno] = entry;
- if (_arc_aux_read(AUX_BCR_D_CACHE) > 0x2) {
- /* dcache is available */
- dcache_flush_line((uint32_t)&table[excno]);
- }
- if (_arc_aux_read(AUX_BCR_D_CACHE) > 0x2) {
- /* icache is available */
- icache_invalidate_line((uint32_t)&table[excno]);
- }
- cpu_unlock_restore(status);
- return 0;
- }
- return -1;
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_CPU
- * \brief get the installed CPU exception entry
- * \param[in] excno exception number
- * \return the installed CPU exception entry
- */
- EXC_ENTRY exc_entry_get(const uint32_t excno)
- {
- if (excno < NUM_EXC_ALL) {
- return exc_entry_table[excno];
- }
- return NULL;
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_CPU
- * \brief install an exception handler
- * \param[in] excno exception number
- * \param[in] handler the handler of exception to install
- */
- int32_t exc_handler_install(const uint32_t excno, EXC_HANDLER handler)
- {
- if (excno < NUM_EXC_ALL && handler != NULL) {
- exc_int_handler_table[excno] = handler;
- return 0;
- }
- return -1;
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_CPU
- * \brief get the installed exception handler
- * \param[in] excno exception number
- * \return the installed exception handler or NULL
- */
- EXC_HANDLER exc_handler_get(const uint32_t excno)
- {
- if (excno < NUM_EXC_ALL) {
- return exc_int_handler_table[excno];
- }
- return NULL;
- }
- #ifndef EMBARC_OVERRIDE_ARC_INTERRUPT_MANAGEMENT
- /**
- * \brief disable the specific interrupt
- *
- * \param[in] intno interrupt number
- */
- int32_t int_disable(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- arc_int_disable(intno);
- return 0;
- }
- return -1;
- }
- /**
- * \brief enable the specific int
- *
- * \param[in] intno interrupt number
- */
- int32_t int_enable(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- arc_int_enable(intno);
- return 0;
- }
- return -1;
- }
- /**
- * \brief check whether the specific int is enabled
- *
- * \param[in] intno interrupt number
- * \return 0 disabled, 1 enabled, < 0 error
- */
- int32_t int_enabled(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- _arc_aux_write(AUX_IRQ_SELECT, intno);
- return _arc_aux_read(AUX_IRQ_ENABLE);
- }
- return -1;
- }
- /**
- * \brief get the interrupt priority mask
- *
- * \returns interrupt priority mask, negative num
- */
- int32_t int_ipm_get(void)
- {
- return ((int32_t)arc_int_ipm_get() + INT_PRI_MIN);
- }
- /**
- * \brief set the interrupt priority mask
- *
- * \param[in] intpri interrupt priority
- */
- int32_t int_ipm_set(int32_t intpri)
- {
- if (intpri >= INT_PRI_MIN && intpri <= INT_PRI_MAX) {
- intpri = intpri - INT_PRI_MIN;
- arc_int_ipm_set(intpri);
- return 0;
- }
- return -1;
- }
- /**
- * \brief get current interrupt priority mask
- *
- * \param[in] intno interrupt number
- * \return <0 interrupt priority, 0 error
- */
- int32_t int_pri_get(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- return (int32_t)arc_int_pri_get(intno) + INT_PRI_MIN;
- }
- return 0;
- }
- /**
- * \brief set interrupt priority
- *
- * \param[in] intno interrupt number
- * \param[in] intpri interrupt priority
- * \return <0 error, 0 ok
- */
- int32_t int_pri_set(const uint32_t intno, int32_t intpri)
- {
- uint32_t status;
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- status = cpu_lock_save();
- intpri = intpri - INT_PRI_MIN;
- arc_int_pri_set(intno,(uint32_t)intpri);
- cpu_unlock_restore(status);
- return 0;
- }
- return -1;
- }
- /**
- * \brief set interrupt secure or not secure
- * This function is valid in secureshield v2
- * \param[in] intno interrupt number
- * \param[in] secure, 0 for normal, >0 for secure
- * \return <0 error, 0 ok
- */
- int32_t int_secure_set(const uint32_t intno, uint32_t secure)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- arc_int_secure_set(intno, secure);
- return 0;
- }
- return -1;
- }
- /**
- * \brief probe the pending status of interrupt
- *
- * \param[in] intno interrupt number
- *
- * \returns 1 pending, 0 no pending, -1 error
- */
- int32_t int_probe(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- return arc_int_probe(intno);
- }
- return -1;
- }
- /**
- * \brief trigger the interrupt in software
- *
- * \param[in] intno interrupt number
- * \return 0 ok, -1 error
- */
- int32_t int_sw_trigger(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- arc_int_sw_trigger(intno);
- return 0;
- }
- return -1;
- }
- /**
- * \brief config the interrupt level triggered or pulse triggered
- *
- * \param[in] intno interrupt number
- * \param[in] level, 0-level trigger, 1-pulse triggered
- * \return 0 ok, -1 error
- */
- int32_t int_level_config(const uint32_t intno, const uint32_t level)
- {
- if (intno >= NUM_EXC_CPU && intno < NUM_EXC_ALL) {
- arc_int_level_config(intno, level);
- return 0;
- }
- return -1;
- }
- /**
- * \brief lock cpu, disable interrupts
- */
- void cpu_lock(void)
- {
- arc_lock();
- }
- /**
- * \brief unlock cpu, enable interrupts to happen
- */
- void cpu_unlock(void)
- {
- arc_unlock();
- }
- /**
- * \brief lock cpu and return status
- *
- * \returns cpu status
- */
- uint32_t cpu_lock_save(void)
- {
- return arc_lock_save();
- }
- /**
- * \brief unlock cpu with the specific status
- *
- * \param[in] status cpu status saved by cpu_lock_save
- */
- void cpu_unlock_restore(const uint32_t status)
- {
- arc_unlock_restore(status);
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_INTERRUPT
- * \brief install an interrupt handler
- * \param[in] intno interrupt number
- * \param[in] handler interrupt handler to install
- */
- int32_t int_handler_install(const uint32_t intno, INT_HANDLER handler)
- {
- /*!< \todo parameter check ? */
- if (intno >= NUM_EXC_CPU) {
- return exc_handler_install(intno, handler);
- }
- return -1;
- }
- /**
- * \ingroup ARC_HAL_EXCEPTION_INTERRUPT
- * \brief get the installed an interrupt handler
- * \param[in] intno interrupt number
- * \return the installed interrupt handler or NULL
- */
- INT_HANDLER int_handler_get(const uint32_t intno)
- {
- if (intno >= NUM_EXC_CPU) {
- return exc_handler_get(intno);
- }
- return NULL;
- }
- #endif /* EMBARC_OVERRIDE_ARC_INTERRUPT_MANAGEMENT */
|