Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

armv8-r/gicv3: support fiq #14929

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions arch/arm/include/armv8-r/cp15.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
4 changes: 2 additions & 2 deletions arch/arm/include/armv8-r/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions arch/arm/src/armv8-r/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
12 changes: 0 additions & 12 deletions arch/arm/src/armv8-r/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions arch/arm/src/armv8-r/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -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
61 changes: 61 additions & 0 deletions arch/arm/src/armv8-r/arm_dofiq.c
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 5 additions & 0 deletions arch/arm/src/armv8-r/arm_gic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
134 changes: 128 additions & 6 deletions arch/arm/src/armv8-r/arm_gicv3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -676,11 +753,56 @@ void up_trigger_irq(int irq, cpu_set_t cpuset)
}
}

#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
/***************************************************************************
* Name: arm_decodefiq
*
* Description:
* 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: arm64_decodeirq
* Name: arm_decodeirq
*
* Description:
* This function is called from the IRQ vector handler in arm64_vectors.S.
* 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
Expand Down
6 changes: 3 additions & 3 deletions arch/arm/src/armv8-r/arm_initialstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions arch/arm/src/armv8-r/arm_vectors.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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. */

Expand Down Expand Up @@ -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
Expand Down
Loading