arm64 support gicv2m for pci irq
Signed-off-by: yezhonghui <yezhonghui@xiaomi.com>
This commit is contained in:
parent
45bb7a9c1c
commit
52ffca5b8e
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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 */
|
||||
|
154
arch/arm64/src/common/arm64_gicv2m.c
Normal file
154
arch/arm64/src/common/arm64_gicv2m.c
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user