arm64 support gicv2m for pci irq

Signed-off-by: yezhonghui <yezhonghui@xiaomi.com>
This commit is contained in:
yezhonghui 2024-08-15 17:15:06 +08:00 committed by Mateusz Szafoni
parent 45bb7a9c1c
commit 52ffca5b8e
7 changed files with 258 additions and 53 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -321,6 +321,11 @@ uint64_t * arm64_decodeirq(uint64_t *regs);
void 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
/****************************************************************************

View File

@ -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"
@ -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
*
@ -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. */
@ -1354,6 +1308,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
*
@ -1393,12 +1398,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);
}
}
@ -1507,4 +1512,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 */

View File

@ -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;
}