arch/mips: When a CPU implements an External Interrupt Controller,

use the IPL bits to control masking interrupts.
This commit is contained in:
Ouss4 2020-02-01 20:51:10 +00:00 committed by patacongo
parent d68693f74c
commit 0dc1dc605d
14 changed files with 84 additions and 78 deletions

View File

@ -11,6 +11,7 @@ choice
config ARCH_CHIP_PIC32MX
bool "PIC32MX"
select ARCH_MIPS32
select ARCH_HAVE_EIC
select ARCH_HAVE_IRQPRIO
select ARCH_VECNOTIRQ
select ARCH_HAVE_RAMFUNCS
@ -21,6 +22,7 @@ config ARCH_CHIP_PIC32MX
config ARCH_CHIP_PIC32MZ
bool "PIC32MZ"
select ARCH_MIPS32
select ARCH_HAVE_EIC
select ARCH_HAVE_IRQPRIO
select ARCH_VECNOTIRQ
select ARCH_HAVE_RAMFUNCS
@ -44,6 +46,10 @@ config ARCH_MIPS_M14K
default n
select ARCH_HAVE_MICROMIPS
config ARCH_HAVE_EIC
bool
default n
config ARCH_HAVE_MICROMIPS
bool
default n

View File

@ -41,6 +41,7 @@
****************************************************************************/
#include <nuttx/config.h>
#include <arch/chip/chip.h>
/****************************************************************************
* Pre-processor Definitions
@ -213,20 +214,27 @@
#define CP0_STATUS_UX (1 << 5) /* Bit 5: Enables 64-bit user address space (Not MIPS32) */
#define CP0_STATUS_SX (1 << 6) /* Bit 6: Enables 64-bit supervisor address space (Not MIPS32) */
#define CP0_STATUS_KX (1 << 7) /* Bit 7: Enables 64-bit kernel address space (Not MIPS32) */
#define CP0_STATUS_IM_SHIFT (8) /* Bits 8-15: Interrupt Mask */
#define CP0_STATUS_IM_MASK (0xff << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM_SWINTS (0x03 << CP0_STATUS_IM_SHIFT) /* IM0-1 = Software interrupts */
# define CP0_STATUS_IM0 (0x01 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM1 (0x02 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM_HWINTS (0x7c << CP0_STATUS_IM_SHIFT) /* IM2-6 = Hardware interrupts */
# define CP0_STATUS_IM2 (0x04 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM3 (0x08 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM4 (0x10 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM5 (0x20 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM6 (0x40 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM_TIMER (0x80 << CP0_STATUS_IM_SHIFT) /* IM7 = Hardware/Timer/Perf interrupts */
# define CP0_STATUS_IM7 (0x80 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM_ALL (0xff << CP0_STATUS_IM_SHIFT)
#ifdef CONFIG_ARCH_HAVE_EIC
# define CP0_STATUS_IPL_SHIFT (10) /* Bits 10-16+18: Interrupt Mask */
# define CP0_STATUS_IPL_MASK (0x17f << CP0_STATUS_IPL_SHIFT)
# define CP0_STATUS_IPL_ENALL (0x00 << CP0_STATUS_IPL_SHIFT)
# define CP0_STATUS_IPL_SW0 ((CHIP_MAX_PRIORITY - 1) << CP0_STATUS_IPL_SHIFT)
# define CP0_STATUS_IPL_DISALL (CHIP_MAX_PRIORITY << CP0_STATUS_IPL_SHIFT)
# define CP0_STATUS_INT_ENALL CP0_STATUS_IPL_ENALL
# define CP0_STATUS_INT_SW0 CP0_STATUS_IPL_SW0
# define CP0_STATUS_INT_MASK CP0_STATUS_IPL_MASK
# define CP0_STATUS_INT_DISALL CP0_STATUS_IPL_DISALL
#else
# define CP0_STATUS_IM_SHIFT (8) /* Bits 8-15: Interrupt Mask */
# define CP0_STATUS_IM_MASK (0xff << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM_DISALL (0x00 << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_IM_SW0 (0x03 << CP0_STATUS_IM_SHIFT) /* IM0-1 = Software interrupts */
# define CP0_STATUS_IM_ALL (0xff << CP0_STATUS_IM_SHIFT)
# define CP0_STATUS_INT_ENALL CP0_STATUS_IM_ALL
# define CP0_STATUS_INT_SW0 CP0_STATUS_IM_SW0
# define CP0_STATUS_INT_MASK CP0_STATUS_IM_MASK
# define CP0_STATUS_INT_DISALL CP0_STATUS_IM_DISALL
#endif
#define CP0_STATUS_IMPL_SHIFT (16) /* Bits 16-17: Implementation dependent */
#define CP0_STATUS_IMPL_MASK (3 << CP0_STATUS_IMPL_SHIFT)
#define CP0_STATUS_NMI (1 << 19) /* Bit 19: Reset exception due to an NMI */

View File

@ -33,7 +33,7 @@
*
****************************************************************************/
/* This file should never be included directed but, rather, only indirectly
/* This file should never be included directly but, rather, only indirectly
* through include/syscall.h or include/sys/sycall.h
*/

View File

@ -2400,6 +2400,14 @@
# error "Unrecognized PIC32 device
#endif
/* IPL priority levels *****************************************************/
/* These priorities will be used by the core to properly disable/mask
* interrupts.
*/
#define CHIP_MIN_PRIORITY 1 /* Minimum priority. */
#define CHIP_MAX_PRIORITY 7 /* Maximum priority. */
/****************************************************************************
* Public Types
****************************************************************************/

View File

@ -140,17 +140,15 @@
#undef CP0_STATUS_PX
#undef CP0_STATUS_MX
/* 2. The following field is of a different width. Apparently, it
* excludes the software interrupt bits.
/* 2. The following field is of a different width.
*
* CP0_STATUS_IM Bits 8-15: Interrupt Mask
* Vs.
* CP0_STATUS_IPL Bits 10-15: Interrupt priority level
* CP0_STATUS_IPL Bits 10-12: Interrupt priority level
* Bitss 8-9 reserved
*/
#define CP0_STATUS_IPL_SHIFT (10) /* Bits 10-15: Interrupt priority level */
#define CP0_STATUS_IPL_MASK (0x3f << CP0_STATUS_IPL_SHIFT)
#undef CP0_STATUS_IPL_MASK
#define CP0_STATUS_IPL_MASK (0x07 << CP0_STATUS_IPL_SHIFT)
/* 3. Supervisor mode not supported
* CP0_STATUS_KSU Bits 3-4: Operating mode (with supervisor mode)

View File

@ -198,6 +198,14 @@
# error "Unrecognized PIC32MZ device"
#endif
/* IPL priority levels *****************************************************/
/* These priorities will be used by the core to properly disable/mask
* interrupts.
*/
#define CHIP_MIN_PRIORITY 1 /* Minimum priority. */
#define CHIP_MAX_PRIORITY 7 /* Maximum priority. */
/****************************************************************************
* Public Types
****************************************************************************/

View File

@ -211,7 +211,7 @@
* CP0_STATUS_IMPL Bits 16-17: Implementation dependent
* CP0_STATUS_PX Bit 23: Enables 64-bit operations (Not MIPS32)
* CP0_STATUS_FR Bit 26: Controls the floating point register mode (Not MIPS32)
* CP0_STATUS_MX Bit 24: Enables MDMX (Not MIPS32)
* CP0_STATUS_MX Bit 24: Enables MDMX (Not MIPS32)
* CP0_STATUS_CU1 Bit 29: Controls access to coprocessor 1
* CP0_STATUS_CU2 Bit 30: Controls access to coprocessor 2
* CP0_STATUS_CU3 Bit 31: Controls access to coprocessor 3
@ -229,18 +229,6 @@
#undef CP0_STATUS_CU2
#undef CP0_STATUS_CU3
/* 2. The following field is of a different width. Apparently, it
* excludes the software interrupt bits.
*
* CP0_STATUS_IM Bits 8-15: Interrupt Mask
* Vs.
* CP0_STATUS_IPL Bits 10-16+18: Interrupt priority level
* Bits 8-9 reserved
*/
#define CP0_STATUS_IPL_SHIFT (10) /* Bits 10-16+18: Interrupt priority level */
#define CP0_STATUS_IPL_MASK (0x17f << CP0_STATUS_IPL_SHIFT)
/* 3. Supervisor mode not supported
* CP0_STATUS_KSU Bits 3-4: Operating mode (with supervisor mode)
*/

View File

@ -33,7 +33,7 @@
*
****************************************************************************/
/* This file should never be included directed but, rather, only indirectly
/* This file should never be included directly but, rather, only indirectly
* through include/syscall.h or include/sys/sycall.h
*/
@ -44,10 +44,10 @@
* Included Files
****************************************************************************/
/* Include ARM architecture-specific syscall macros */
/* Include MIPS architecture-specific syscall macros */
#ifdef CONFIG_ARCH_MIPS32
# include <arch/mips32/syscall.h>
# include <arch/mips32/syscall.h>
#endif
/****************************************************************************

View File

@ -69,23 +69,9 @@ void up_idle(void)
nxsched_process_timer();
#else
irqstate_t flags;
/* This would be an appropriate place to put some MCU-specific logic to
* sleep in a reduced power mode until an interrupt occurs to save power
*/
/* This is a kludge that I still don't understand. It appears that we are
* somehow left idling with interrupts non-functional. The following should
* be no-op, it just disables then re-enables interrupts. But it fixes the
* problem and will stay here until I understand the problem/fix better.
*
* And no, the contents of the CP0 status register are not incorrect. But
* for some reason the status register needs to be re-written again on this
* thread for it to take effect. This might be a PIC32-only issue?
*/
flags = up_irq_save();
up_irq_restore(flags);
#endif
}

View File

@ -125,11 +125,12 @@ void up_initial_state(struct tcb_s *tcb)
regval = cp0_getstatus();
#ifdef CONFIG_SUPPRESS_INTERRUPTS
regval &= ~(CP0_STATUS_IM_ALL | CP0_STATUS_BEV | CP0_STATUS_UM);
regval |= (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_IM_SWINTS);
regval &= ~(CP0_STATUS_INT_MASK | CP0_STATUS_BEV | CP0_STATUS_UM);
regval |= (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_INT_SW0);
#else
regval &= ~(CP0_STATUS_BEV | CP0_STATUS_UM);
regval |= (CP0_STATUS_IE | CP0_STATUS_EXL | CP0_STATUS_IM_ALL);
regval &= ~CP0_STATUS_INT_MASK;
regval |= (CP0_STATUS_IE | CP0_STATUS_EXL);
#endif
xcp->regs[REG_STATUS] = regval;
}

View File

@ -68,10 +68,10 @@ irqstate_t up_irq_save(void)
status = cp0_getstatus(); /* Get CP0 status */
ret = status; /* Save the status */
status &= ~CP0_STATUS_IM_MASK; /* Clear all interrupt mask bits */
status |= CP0_STATUS_IM_SWINTS; /* Keep S/W interrupts enabled */
cp0_putstatus(status); /* Disable interrupts */
return ret; /* Return status before interrupts disabled */
status &= ~CP0_STATUS_INT_MASK; /* Clear all interrupt mask bits */
status |= CP0_STATUS_INT_SW0; /* Enable only the SW0 interrupt */
cp0_putstatus(status); /* Disable the rest of interrupts */
return ret; /* Return saved status */
}
/****************************************************************************
@ -93,12 +93,11 @@ void up_irq_restore(irqstate_t irqstate)
{
register irqstate_t status;
status = cp0_getstatus(); /* Get CP0 status */
status &= ~CP0_STATUS_IM_MASK; /* Clear all interrupt mask bits */
irqstate &= CP0_STATUS_IM_MASK; /* Retain interrupt mask bits only */
status |= irqstate; /* Set new interrupt mask bits */
status |= CP0_STATUS_IM_SWINTS; /* Make sure that S/W interrupts enabled */
cp0_putstatus(status); /* Restore interrupt state */
status = cp0_getstatus(); /* Get CP0 status */
status &= ~CP0_STATUS_INT_MASK; /* Clear all interrupt mask bits */
irqstate &= CP0_STATUS_INT_MASK; /* Retain interrupt mask bits only */
status |= irqstate; /* Set new interrupt mask bits */
cp0_putstatus(status); /* Restore interrupt state */
}
/****************************************************************************
@ -125,13 +124,13 @@ void up_irq_enable(void)
* 1. Clear the BEV bit (This bit should already be clear)
* 2. Clear the UM bit so that the task executes in kernel mode
* (This bit should already be clear)
* 3. Make sure the IE is set
* 4. Make sure the S/W interrupts are enabled
* 5. Set the interrupt mask bits
* 3. Clear all the Interrupt mask bits.
* 4. Make sure the IE is set
*/
status = cp0_getstatus();
status &= ~(CP0_STATUS_BEV | CP0_STATUS_UM);
status |= (CP0_STATUS_IE | CP0_STATUS_IM_SWINTS | CP0_STATUS_IM_ALL);
status &= ~CP0_STATUS_INT_MASK;
status |= CP0_STATUS_IE;
cp0_putstatus(status);
}

View File

@ -62,7 +62,7 @@
* This function is called by the OS when one or more
* signal handling actions have been queued for execution.
* The architecture specific code must configure things so
* that the 'igdeliver' callback is executed on the thread
* that the 'sigdeliver' callback is executed on the thread
* specified by 'tcb' as soon as possible.
*
* This function may be called from interrupt handling logic.
@ -152,8 +152,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
CURRENT_REGS[REG_EPC] = (uint32_t)up_sigdeliver;
status = CURRENT_REGS[REG_STATUS];
status &= ~CP0_STATUS_IM_MASK;
status |= CP0_STATUS_IM_SWINTS;
status &= ~CP0_STATUS_INT_MASK;
status |= CP0_STATUS_INT_SW0;
CURRENT_REGS[REG_STATUS] = status;
/* And make sure that the saved context in the TCB
@ -191,8 +191,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.regs[REG_EPC] = (uint32_t)up_sigdeliver;
status = tcb->xcp.regs[REG_STATUS];
status &= ~CP0_STATUS_IM_MASK;
status |= CP0_STATUS_IM_SWINTS;
status &= ~CP0_STATUS_INT_MASK;
status |= CP0_STATUS_INT_SW0;
tcb->xcp.regs[REG_STATUS] = status;
sinfo("PC/STATUS Saved: %08x/%08x New: %08x/%08x\n",

View File

@ -172,11 +172,11 @@ void up_irqinitialize(void)
#ifndef CONFIG_SUPPRESS_INTERRUPTS
/* Then enable all interrupt levels */
up_irq_restore(CP0_STATUS_IM_ALL);
up_irq_restore(CP0_STATUS_INT_ENALL);
#else
/* Enable only software interrupts */
up_irq_restore(CP0_STATUS_IM_SWINTS);
up_irq_restore(CP0_STATUS_INT_SW0);
#endif
}

View File

@ -200,6 +200,10 @@ void up_irqinitialize(void)
pic32mz_prioritize_irq(irq, (INT_IPC_MID_PRIORITY << 2));
}
/* Set the Software Interrupt0 to a special priority */
pic32mz_prioritize_irq(1, 7 << 2);
/* Set the BEV bit in the STATUS register */
regval = cp0_getstatus();
@ -261,11 +265,11 @@ void up_irqinitialize(void)
#ifndef CONFIG_SUPPRESS_INTERRUPTS
/* Then enable all interrupt levels */
up_irq_restore(CP0_STATUS_IM_ALL);
up_irq_restore(CP0_STATUS_INT_ENALL);
#else
/* Enable only software interrupts */
up_irq_restore(CP0_STATUS_IM_SWINTS);
up_irq_restore(CP0_STATUS_INT_SW0);
#endif
}