armv8-r/gicv3: support fiq

1. support fiq decoding and dispatch
2. replace CONFIG_ARMV8R_DECODEFIQ with CONFIG_ARCH_HIPRI_INTERRUPT

Signed-off-by: Jinliang Li <lijinliang1@lixiang.com>
This commit is contained in:
Jinliang Li 2024-11-14 00:01:02 +08:00 committed by Xiang Xiao
parent 825ba8ed7b
commit 37a0445ddb
11 changed files with 218 additions and 30 deletions

View file

@ -90,7 +90,8 @@ config ARCH_CHIP_FVP_ARMV8R_AARCH32
select ARCH_CORTEXR52
select ARCH_HAVE_LOWVECTORS
select ARCH_HAVE_FETCHADD
select ARMV8R_HAVE_DECODEFIQ
select ARCH_HAVE_IRQPRIO
select ARCH_HAVE_HIPRI_INTERRUPT
select ARCH_HAVE_FPU
---help---
ARM FVP virt platform (ARMv8r)

View file

@ -170,10 +170,13 @@
#define CP15_DCIALLU(r) _CP15(0, r, c15, c5, 0) /* Invalidate data cache */
#define CP15_ICC_PMR(r) _CP15(0, r, c4, c6, 0) /* ICC_PMR */
#define CP15_ICC_IAR0(r) _CP15(0, r, c12, c8, 0) /* ICC_IAR0 */
#define CP15_ICC_IAR1(r) _CP15(0, r, c12, c12, 0) /* ICC_IAR1 */
#define CP15_ICC_EOIR0(r) _CP15(0, r, c12, c8, 1) /* ICC_EOIR0 */
#define CP15_ICC_EOIR1(r) _CP15(0, r, c12, c12, 1) /* ICC_EOIR1 */
#define CP15_ICC_SRE(r) _CP15(0, r, c12, c12, 5) /* ICC_SRE */
#define CP15_ICC_HSRE(r) _CP15(4, r, c12, c9, 5) /* ICC_HSRE */
#define CP15_ICC_IGRPEN0(r) _CP15(0, r, c12, c12, 6) /* ICC_IGRPEN0 */
#define CP15_ICC_IGRPEN1(r) _CP15(0, r, c12, c12, 7) /* ICC_IGRPEN1 */
#define CP15_ICC_SGI1R(lo,hi) _CP15_64(0, lo, hi, c12) /* ICC_SGI1R */

View file

@ -365,7 +365,7 @@ noinstrument_function static inline irqstate_t up_irq_save(void)
(
"\tmrs %0, cpsr\n"
"\tcpsid i\n"
#if defined(CONFIG_ARMV8R_DECODEFIQ)
#if defined(CONFIG_ARCH_HIPRI_INTERRUPT)
"\tcpsid f\n"
#endif
: "=r" (cpsr)
@ -386,7 +386,7 @@ static inline irqstate_t up_irq_enable(void)
(
"\tmrs %0, cpsr\n"
"\tcpsie i\n"
#if defined(CONFIG_ARMV8R_DECODEFIQ)
#if defined(CONFIG_ARCH_HIPRI_INTERRUPT)
"\tcpsie f\n"
#endif
: "=r" (cpsr)

View file

@ -51,4 +51,8 @@ if(CONFIG_ARCH_FPU)
list(APPEND SRCS arm_fpucmp.c arm_fpuconfig.S)
endif()
if(CONFIG_ARCH_HIPRI_INTERRUPT)
list(APPEND SRCS arm_dofiq.c)
endif()
target_sources(arch PRIVATE ${SRCS})

View file

@ -43,18 +43,6 @@ config ARMV8R_MEMINIT
the memory initialization first, then explicitly call
arm_data_initialize().
config ARMV8R_HAVE_DECODEFIQ
bool
default n
config ARMV8R_DECODEFIQ
bool "FIQ Handler"
default n
depends on ARMV8R_HAVE_DECODEFIQ
---help---
Select this option if your platform supports the function
arm_decodefiq().
config ARMV8R_ALIGNMENT_TRAP
bool "Enable Alignment Check at __start"
default n

View file

@ -52,3 +52,7 @@ endif
ifeq ($(CONFIG_ARMV8R_L2CC_PL310),y)
CMN_CSRCS += arm_l2cc_pl310.c
endif
ifeq ($(CONFIG_ARCH_HIPRI_INTERRUPT),y)
CMN_CSRCS += arm_dofiq.c
endif

View file

@ -0,0 +1,61 @@
/****************************************************************************
* arch/arm/src/armv8-r/arm_dofiq.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: arm_dofiq
*
* Description:
* Receives the decoded GIC interrupt information and dispatches control
* to the attached fiq handler. It is not allowed to call OS functions
* within a FIQ handler.
*
****************************************************************************/
uint32_t *arm_dofiq(int fiq, uint32_t *regs)
{
board_autoled_on(LED_INIRQ);
#ifdef CONFIG_SUPPRESS_INTERRUPTS
PANIC();
#else
irq_dispatch(fiq, regs);
#endif
board_autoled_off(LED_INIRQ);
return regs;
}

View file

@ -328,6 +328,11 @@ bool arm_gic_irq_is_enabled(unsigned int intid);
int arm_gic_initialize(void);
void arm_gic_irq_set_priority(unsigned int intid, unsigned int prio,
uint32_t flags);
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
void arm_gic_set_group(unsigned int intid, unsigned int group);
#endif
int arm_gic_irq_trigger(unsigned int intid, uint32_t flags);
int arm_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list);

View file

@ -279,6 +279,68 @@ bool arm_gic_irq_is_enabled(unsigned int intid)
return (val & mask) != 0;
}
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
void arm_gic_set_group(unsigned int intid, unsigned int group)
{
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
unsigned long base = GET_DIST_BASE(intid);
uint32_t igroupr_val;
uint32_t igroupmodr_val;
igroupr_val = getreg32(IGROUPR(base, idx));
igroupmodr_val = getreg32(IGROUPMODR(base, idx));
if (group == 0)
{
igroupr_val &= ~mask;
igroupmodr_val &= ~mask;
}
else
{
igroupr_val |= mask;
igroupmodr_val |= mask;
}
putreg32(igroupr_val, IGROUPR(base, idx));
putreg32(igroupmodr_val, IGROUPMODR(base, idx));
}
static unsigned int arm_gic_get_active_group0(void)
{
int intid;
/* (Pending -> Active / AP) or (AP -> AP)
* Read a Group 0 INTID on an interrupt acknowledge.
*/
intid = CP15_GET(ICC_IAR0);
return intid;
}
static void arm_gic_eoi_group0(unsigned int intid)
{
/* Interrupt request deassertion from peripheral to GIC happens
* by clearing interrupt condition by a write to the peripheral
* register. It is desired that the write transfer is complete
* before the core tries to change GIC state from 'AP/Active' to
* a new state on seeing 'EOI write'.
* Since ICC interface writes are not ordered against Device
* memory writes, a barrier is required to ensure the ordering.
* The dsb will also ensure *completion* of previous writes with
* DEVICE nGnRnE attribute.
*/
ARM_DSB();
/* (AP -> Pending) Or (Active -> Inactive) or (AP to AP) nested case
* Write a Group 0 interrupt completion
*/
CP15_SET(ICC_EOIR0, intid);
}
#endif
unsigned int arm_gic_get_active(void)
{
int intid;
@ -458,6 +520,12 @@ static void gicv3_cpuif_init(void)
CP15_SET(ICC_PMR, GIC_IDLE_PRIO);
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
/* Allow group0 interrupts */
CP15_SET(ICC_IGRPEN0, 1);
#endif
/* Allow group1 interrupts */
CP15_SET(ICC_IGRPEN1, 1);
@ -560,14 +628,23 @@ static void gicv3_dist_init(void)
* BIT(1), we can reuse them.
*/
putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS),
GICD_CTLR);
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS) |
BIT(GICD_CTLR_ENABLE_G0), GICD_CTLR);
#else
putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS), GICD_CTLR);
#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */
#else
/* Enable distributor with ARE */
putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS),
GICD_CTLR);
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS) |
BIT(GICD_CTLR_ENABLE_G0), GICD_CTLR);
#else
putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS), GICD_CTLR);
#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */
#endif
#ifdef CONFIG_SMP
@ -676,11 +753,56 @@ void up_trigger_irq(int irq, cpu_set_t cpuset)
}
}
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
/***************************************************************************
* Name: arm64_decodeirq
* Name: arm_decodefiq
*
* Description:
* This function is called from the IRQ vector handler in arm64_vectors.S.
* This function is called from the FIQ vector handler in arm_vectors.S.
* At this point, the interrupt has been taken and the registers have
* been saved on the stack. This function simply needs to determine the
* the irq number of the interrupt and then to call arm_dofiq to dispatch
* the interrupt.
*
* Input Parameters:
* regs - A pointer to the register save area on the stack.
***************************************************************************/
uint32_t *arm_decodefiq(uint32_t *regs)
{
int fiq;
/* Read the Group0 interrupt acknowledge register
* and get the interrupt ID
*/
fiq = arm_gic_get_active_group0();
/* Ignore spurions FIQs. ICCIAR will report 1023 if there is no pending
* interrupt.
*/
DEBUGASSERT(fiq < NR_IRQS || fiq == 1023);
if (fiq < NR_IRQS)
{
/* Dispatch the fiq interrupt */
regs = arm_dofiq(fiq, regs);
}
/* Write to Group0 the end-of-interrupt register */
arm_gic_eoi_group0(fiq);
return regs;
}
#endif
/***************************************************************************
* Name: arm_decodeirq
*
* Description:
* This function is called from the IRQ vector handler in arm_vectors.S.
* At this point, the interrupt has been taken and the registers have
* been saved on the stack. This function simply needs to determine the
* the irq number of the interrupt and then to call arm_doirq to dispatch

View file

@ -131,13 +131,13 @@ void up_initial_state(struct tcb_s *tcb)
cpsr |= (PSR_I_BIT | PSR_F_BIT);
#else /* CONFIG_SUPPRESS_INTERRUPTS */
/* Leave IRQs enabled (Also FIQs if CONFIG_ARMV8R_DECODEFIQ is selected) */
/* Leave IRQs enabled (Also FIQs if CONFIG_ARCH_HIPRI_INTERRUPT is selected) */
#ifndef CONFIG_ARMV8R_DECODEFIQ
#ifndef CONFIG_ARCH_HIPRI_INTERRUPT
cpsr |= PSR_F_BIT;
#endif /* !CONFIG_ARMV8R_DECODEFIQ */
#endif /* !CONFIG_ARCH_HIPRI_INTERRUPT */
#ifdef CONFIG_ARM_THUMB
cpsr |= PSR_T_BIT;

View file

@ -163,7 +163,7 @@ arm_vectorirq:
/* Switch to SYS mode */
#ifdef CONFIG_ARMV8R_DECODEFIQ
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
cpsid if, #PSR_MODE_SYS
#else
cpsid i, #PSR_MODE_SYS
@ -273,7 +273,7 @@ arm_vectorsvc:
/* Switch to SYS mode */
#ifdef CONFIG_ARMV8R_DECODEFIQ
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
cpsid if, #PSR_MODE_SYS
#else
cpsid i, #PSR_MODE_SYS
@ -384,7 +384,7 @@ arm_vectordata:
/* Switch to SYS mode */
#ifdef CONFIG_ARMV8R_DECODEFIQ
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
cpsid if, #PSR_MODE_SYS
#else
cpsid i, #PSR_MODE_SYS
@ -625,14 +625,14 @@ arm_vectorundefinsn:
*
****************************************************************************/
#ifdef CONFIG_ARMV8R_DECODEFIQ
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
.globl arm_decodefiq
#endif
.globl arm_vectorfiq
.type arm_vectorfiq, %function
arm_vectorfiq:
#ifdef CONFIG_ARMV8R_DECODEFIQ
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
/* Save the LR and SPSR onto the SYS mode stack before switch. */
@ -754,7 +754,7 @@ g_intstacktop:
* Name: g_fiqstackalloc/g_fiqstacktop
****************************************************************************/
#ifdef CONFIG_ARMV8R_DECODEFIQ
#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
.globl g_fiqstackalloc
.type g_fiqstackalloc, object
.globl g_fiqstacktop