arch/mips: When a CPU implements an External Interrupt Controller,
use the IPL bits to control masking interrupts.
This commit is contained in:
parent
d68693f74c
commit
0dc1dc605d
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user