Skip to content

Commit

Permalink
arm64 support gicv2m for pci irq
Browse files Browse the repository at this point in the history
Signed-off-by: yezhonghui <[email protected]>
  • Loading branch information
yezhonghui2024 authored and xiaoxiang781216 committed Sep 28, 2024
1 parent 48ecb6f commit f81c844
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 53 deletions.
11 changes: 11 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,17 @@ config ARM64_GIC_EOIMODE
Enable GICC_CTLR.EOImode, this will separates the priority drop and interrupt
deactivation operations.

config ARM64_GICV2M
bool "gicv2m support message irq"
depends on PCI_MSIX
default n

config ARM64_GICV2_LEGACY_IRQ0
int "pci legacy irq0 default val"
default 35
---help---
qemu pci legacy irq0 val, not support if val < 0

endif

config ARM64_SEMIHOSTING_HOSTFS
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/include/qemu/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

#define CONFIG_GICD_BASE 0x8000000
#define CONFIG_GICR_BASE 0x8010000
#define CONFIG_GICM_BASE 0x8020000

#elif CONFIG_ARM64_GIC_VERSION == 3 || CONFIG_ARM64_GIC_VERSION == 4

Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ endif()

if(CONFIG_ARM64_GIC_VERSION EQUAL 2)
list(APPEND SRCS arm64_gicv2.c)
if(CONFIG_ARM64_GICV2M)
list(APPEND SRCS arm64_gicv2m.c)
endif()
endif()

if(CONFIG_ARCH_HAVE_MMU)
Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/src/common/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ endif

ifeq ($(CONFIG_ARM64_GIC_VERSION),2)
CMN_CSRCS += arm64_gicv2.c
ifeq ($(CONFIG_ARM64_GICV2M),y)
CMN_CSRCS += arm64_gicv2m.c
endif
endif

ifeq ($(CONFIG_ARCH_HAVE_MMU),y)
Expand Down
5 changes: 5 additions & 0 deletions arch/arm64/src/common/arm64_gic.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ uint64_t * arm64_decodeirq(uint64_t *regs);

int arm64_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list);

int arm64_gicv_irq_trigger(int irq, bool edge);
#ifdef CONFIG_ARM64_GICV2M
int arm64_gic_v2m_initialize(void);
#endif

#ifdef CONFIG_SMP

/****************************************************************************
Expand Down
134 changes: 81 additions & 53 deletions arch/arm64/src/common/arm64_gicv2.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

#include <nuttx/arch.h>
#include <arch/irq.h>
#include <nuttx/pci/pci.h>

#include "arm64_internal.h"
#include "arm64_gic.h"
Expand Down Expand Up @@ -795,57 +796,6 @@ static int gic_validate_dist_version(void)
return 0;
}

/****************************************************************************
* Name: arm_gic_irq_trigger
*
* Description:
* Set the trigger type for the specified IRQ source and the current CPU.
*
* Since this API is not supported on all architectures, it should be
* avoided in common implementations where possible.
*
* Input Parameters:
* irq - The interrupt request to modify.
* edge - False: Active HIGH level sensitive, True: Rising edge sensitive
*
* Returned Value:
* Zero (OK) on success; a negated errno value is returned on any failure.
*
****************************************************************************/

static int arm_gic_irq_trigger(int irq, bool edge)
{
uintptr_t regaddr;
uint32_t regval;
uint32_t intcfg;

if (irq > GIC_IRQ_SGI15 && irq < NR_IRQS)
{
/* Get the address of the Interrupt Configuration Register for this
* irq.
*/

regaddr = GIC_ICDICFR(irq);

/* Get the new Interrupt configuration bit setting */

intcfg = (edge ? (INT_ICDICFR_EDGE | INT_ICDICFR_1N) : INT_ICDICFR_1N);

/* Write the correct interrupt trigger to the Interrupt Configuration
* Register.
*/

regval = getreg32(regaddr);
regval &= ~GIC_ICDICFR_ID_MASK(irq);
regval |= GIC_ICDICFR_ID(irq, intcfg);
putreg32(regval, regaddr);

return OK;
}

return -EINVAL;
}

/****************************************************************************
* Name: arm_gic0_initialize
*
Expand Down Expand Up @@ -907,6 +857,10 @@ static void arm_gic0_initialize(void)
putreg32(0x01010101, GIC_ICDIPTR(irq)); /* SPI on CPU0 */
}

#ifdef CONFIG_ARM64_GICV2M
arm64_gic_v2m_initialize();
#endif

#ifdef CONFIG_SMP
/* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */

Expand Down Expand Up @@ -1352,6 +1306,57 @@ void up_trigger_irq(int irq, cpu_set_t cpuset)
}
}

/****************************************************************************
* Name: arm64_gicv_irq_trigger
*
* Description:
* Set the trigger type for the specified IRQ source and the current CPU.
*
* Since this API is not supported on all architectures, it should be
* avoided in common implementations where possible.
*
* Input Parameters:
* irq - The interrupt request to modify.
* edge - False: Active HIGH level sensitive, True: Rising edge sensitive
*
* Returned Value:
* Zero (OK) on success; a negated errno value is returned on any failure.
*
****************************************************************************/

int arm64_gicv_irq_trigger(int irq, bool edge)
{
uintptr_t regaddr;
uint32_t regval;
uint32_t intcfg;

if (irq > GIC_IRQ_SGI15 && irq < NR_IRQS)
{
/* Get the address of the Interrupt Configuration Register for this
* irq.
*/

regaddr = GIC_ICDICFR(irq);

/* Get the new Interrupt configuration bit setting */

intcfg = (edge ? (INT_ICDICFR_EDGE | INT_ICDICFR_1N) : INT_ICDICFR_1N);

/* Write the correct interrupt trigger to the Interrupt Configuration
* Register.
*/

regval = getreg32(regaddr);
regval &= ~GIC_ICDICFR_ID_MASK(irq);
regval |= GIC_ICDICFR_ID(irq, intcfg);
putreg32(regval, regaddr);

return OK;
}

return -EINVAL;
}

/****************************************************************************
* Name: arm64_gic_irq_set_priority
*
Expand Down Expand Up @@ -1391,12 +1396,12 @@ void arm64_gic_irq_set_priority(unsigned int intid, unsigned int prio,
{
if (flags & IRQ_TYPE_EDGE)
{
ret = arm_gic_irq_trigger(intid, true);
ret = arm64_gicv_irq_trigger(intid, true);
DEBUGASSERT(ret == OK);
}
else
{
ret = arm_gic_irq_trigger(intid, false);
ret = arm64_gicv_irq_trigger(intid, false);
DEBUGASSERT(ret == OK);
}
}
Expand Down Expand Up @@ -1506,4 +1511,27 @@ void up_send_smp_call(cpu_set_t cpuset)
# endif
#endif /* CONFIG_SMP */

/****************************************************************************
* Name: up_get_legacy_irq
*
* Description:
* Reserve vector for legacy
*
****************************************************************************/

int up_get_legacy_irq(uint32_t devfn, uint8_t line, uint8_t pin)
{
#if CONFIG_ARM64_GICV2_LEGACY_IRQ0 >= 0
uint8_t slot;
uint8_t tmp;

UNUSED(line);
slot = PCI_SLOT(devfn);
tmp = (pin - 1 + slot) % 4;
return CONFIG_ARM64_GICV2_LEGACY_IRQ0 + tmp;
#else
return -ENOTSUP;
#endif
}

#endif /* CONFIG_ARM64_GIC_VERSION == 2 */
154 changes: 154 additions & 0 deletions arch/arm64/src/common/arm64_gicv2m.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/****************************************************************************
* arch/arm64/src/common/arm64_gicv2m.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 <errno.h>

#include <nuttx/kmalloc.h>
#include <nuttx/bits.h>
#include <nuttx/spinlock.h>

#include "arm64_internal.h"
#include "arm64_gic.h"

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#define MPCORE_ICM_VBASE CONFIG_GICM_BASE

/* V2m Registers */

#define GIC_V2MTYPER_OFFSET 0x008
#define GIC_V2MSETSPI_OFFSET 0x040
#define GIC_V2MTYPER (MPCORE_ICM_VBASE + GIC_V2MTYPER_OFFSET)
#define GIC_V2MSETSPI (MPCORE_ICM_VBASE + GIC_V2MSETSPI_OFFSET)

#define GIC_V2MTYPES_BASE_SHIFT 16
#define GIC_V2MTYPES_BASE_MASK 0x3FF
#define GIC_V2MTYPES_NUM_MASK 0x3FF
#define GIC_V2MTYPES_BASE(x) \
(((x) >> GIC_V2MTYPES_BASE_SHIFT) & GIC_V2MTYPES_NUM_MASK)
#define GIC_V2MTYPES_NUMBER(x) ((x) & GIC_V2MTYPES_NUM_MASK)

/****************************************************************************
* Private Types
****************************************************************************/

struct gic_v2m_s
{
spinlock_t lock;
uint32_t spi_start;
uint32_t spi_number;
unsigned long *spi_bitmap;
};

/****************************************************************************
* Private Data
****************************************************************************/

static struct gic_v2m_s g_v2m =
{
SP_LOCKED
};

/****************************************************************************
* Private Functions
****************************************************************************/

static bool is_valid_spi(uint32_t base, uint32_t num)
{
if (base < GIC_SPI_INT_BASE)
{
return false;
}

if ((num == 0) || (base + num > NR_IRQS))
{
return false;
}

return true;
}

/****************************************************************************
* Public Functions
****************************************************************************/

int arm64_gic_v2m_initialize(void)
{
uint32_t typer;

typer = getreg32(GIC_V2MTYPER);
g_v2m.spi_start = GIC_V2MTYPES_BASE(typer);
g_v2m.spi_number = GIC_V2MTYPES_NUMBER(typer);

if (!is_valid_spi(g_v2m.spi_start, g_v2m.spi_number))
{
return -EINVAL;
}

g_v2m.spi_bitmap = kmm_zalloc(BITS_TO_LONGS(g_v2m.spi_number));
if (g_v2m.spi_bitmap == NULL)
{
return -ENOMEM;
}

return 0;
}

int up_alloc_irq_msi(FAR int *num)
{
irqstate_t flags;
int offset;
int irq;
int i;

flags = spin_lock_irqsave(&g_v2m.lock);
offset = bitmap_find_free_region(g_v2m.spi_bitmap, g_v2m.spi_number, *num);
spin_unlock_irqrestore(&g_v2m.lock, flags);
irq = g_v2m.spi_start + offset;
for (i = 0; i < *num; i++)
{
arm64_gicv_irq_trigger(i + irq, true);
}

return irq;
}

void up_release_irq_msi(FAR int *irq, int num)
{
irqstate_t flags;

flags = spin_lock_irqsave(&g_v2m.lock);
bitmap_release_region(g_v2m.spi_bitmap, *irq - g_v2m.spi_start, num);
spin_unlock_irqrestore(&g_v2m.lock, flags);
}

int up_connect_irq(FAR int *irq, int num,
FAR uintptr_t *mar, FAR uint32_t *mdr)
{
*mar = GIC_V2MSETSPI;
*mdr = *irq;
return 0;
}

0 comments on commit f81c844

Please sign in to comment.