From 1cb81f9a8f96022491c5f92923aecedbcdecd4ab Mon Sep 17 00:00:00 2001 From: lipengfei28 Date: Fri, 12 Jul 2024 16:05:57 +0800 Subject: [PATCH] armv7a pci irq support Signed-off-by: lipengfei28 --- arch/arm/src/armv7-a/CMakeLists.txt | 4 + arch/arm/src/armv7-a/Kconfig | 11 ++ arch/arm/src/armv7-a/Make.defs | 6 +- arch/arm/src/armv7-a/arm_gicv2.c | 4 + arch/arm/src/armv7-a/arm_gicv2m.c | 162 ++++++++++++++++++++++++++++ arch/arm/src/armv7-a/gic.h | 22 ++++ arch/arm/src/armv7-a/mpcore.h | 1 + arch/arm/src/qemu/chip.h | 1 + drivers/pci/pci_ecam.c | 77 ++++++++++++- 9 files changed, 283 insertions(+), 5 deletions(-) create mode 100644 arch/arm/src/armv7-a/arm_gicv2m.c diff --git a/arch/arm/src/armv7-a/CMakeLists.txt b/arch/arm/src/armv7-a/CMakeLists.txt index cd390645d1..042be6cffb 100644 --- a/arch/arm/src/armv7-a/CMakeLists.txt +++ b/arch/arm/src/armv7-a/CMakeLists.txt @@ -52,6 +52,10 @@ if(CONFIG_ARCH_PERF_EVENTS) list(APPEND SRCS arm_perf.c) endif() +if(CONFIG_ARMV7A_GICv2M) + list(APPEND SRCS arm_gicv2m.c) +endif() + if(CONFIG_ARMV7A_HAVE_PTM) list(APPEND SRCS arm_timer.c) endif() diff --git a/arch/arm/src/armv7-a/Kconfig b/arch/arm/src/armv7-a/Kconfig index e4e0eca96d..dc8db040e8 100644 --- a/arch/arm/src/armv7-a/Kconfig +++ b/arch/arm/src/armv7-a/Kconfig @@ -24,6 +24,17 @@ config ARMV7A_GIC_EOIMODE Enable GICC_CTLR.EOImode, this will separates the priority drop and interrupt deactivation operations. +config ARMV7A_GICV2_LEGACY_IRQ0 + int "pci legacy irq0 default val" + default 35 + ---help--- + The qemu pci lagacy irq0 default is 35. -1 mean disable + +config ARMV7A_GICv2M + bool "gic support msi irq" + depends on PCI_MSIX + default n + endif # ARMV7A_HAVE_GICv2 config ARMV7A_HAVE_GTM diff --git a/arch/arm/src/armv7-a/Make.defs b/arch/arm/src/armv7-a/Make.defs index 331bb62fc1..f757e3d11c 100644 --- a/arch/arm/src/armv7-a/Make.defs +++ b/arch/arm/src/armv7-a/Make.defs @@ -47,7 +47,11 @@ CMN_CSRCS += arm_schedulesigaction.c arm_sigdeliver.c CMN_CSRCS += arm_syscall.c arm_tcbinfo.c arm_undefinedinsn.c CMN_CSRCS += arm_perf.c cp15_cacheops.c -ifeq ($(CONFIG_ARMV7A_HAVE_PTM), y) +ifeq ($(CONFIG_ARMV7A_GICv2M),y) + CMN_CSRCS += arm_gicv2m.c +endif + +ifeq ($(CONFIG_ARMV7A_HAVE_PTM),y) CMN_CSRCS += arm_timer.c endif diff --git a/arch/arm/src/armv7-a/arm_gicv2.c b/arch/arm/src/armv7-a/arm_gicv2.c index 47a132fbc6..f4730ce243 100644 --- a/arch/arm/src/armv7-a/arm_gicv2.c +++ b/arch/arm/src/armv7-a/arm_gicv2.c @@ -210,6 +210,10 @@ void arm_gic0_initialize(void) putreg32(0x01010101, GIC_ICDIPTR(irq)); /* SPI on CPU0 */ } +#ifdef CONFIG_ARMV7A_GICv2M + gic_v2m_initialize(); +#endif + #ifdef CONFIG_SMP /* Attach SGI interrupt handlers. This attaches the handler to all CPUs. */ diff --git a/arch/arm/src/armv7-a/arm_gicv2m.c b/arch/arm/src/armv7-a/arm_gicv2m.c new file mode 100644 index 0000000000..8d96a5c2cb --- /dev/null +++ b/arch/arm/src/armv7-a/arm_gicv2m.c @@ -0,0 +1,162 @@ +/**************************************************************************** + * arch/arm/src/armv7-a/arm_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 + +#include +#include +#include +#include + +#include "arm_internal.h" +#include "gic.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * 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 number) +{ + if (base < GIC_IRQ_SPI) + { + return false; + } + + if (number == 0 || base + number > NR_IRQS) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int 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(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++) + { + arm_gic_irq_trigger(i + irq, true); + } + + return irq; +} + +void up_release_irq_msi(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(int *irq, int num, + uintptr_t *mar, uint32_t *mdr) +{ + *mar = GIC_V2MSETSPI; + *mdr = *irq; + return 0; +} + +/**************************************************************************** + * 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_ARMV7A_GICV2_LEGACY_IRQ0 >= 0 + uint8_t slot; + uint8_t tmp; + + UNUSED(line); + slot = PCI_SLOT(devfn); + tmp = (pin - 1 + slot) % 4; + return CONFIG_ARMV7A_GICV2_LEGACY_IRQ0 + tmp; +#else + return -ENOTSUP; +#endif +} diff --git a/arch/arm/src/armv7-a/gic.h b/arch/arm/src/armv7-a/gic.h index b652dea0a1..ce7cbd0ec6 100644 --- a/arch/arm/src/armv7-a/gic.h +++ b/arch/arm/src/armv7-a/gic.h @@ -136,6 +136,11 @@ /* 0x0020-0x003c: Implementation defined */ /* 0x0040-0x007c: Reserved */ +/* V2M Registers */ + +#define GIC_V2MTYPER_OFFSET 0x008 +#define GIC_V2MSETSPI_OFFSET 0x040 + /* Interrupt Security Registers: 0x0080-0x009c */ #define GIC_ICDISR_OFFSET(n) (0x0080 + GIC_OFFSET32(n)) @@ -277,6 +282,11 @@ #define GIC_ICDPIDR(n) (MPCORE_ICD_VBASE+GIC_ICDPIDR_OFFSET(n)) #define GIC_ICDCIDR(n) (MPCORE_ICD_VBASE+GIC_ICDCIDR_OFFSET(n)) +/* V2M Registers */ + +#define GIC_V2MTYPER (MPCORE_V2M_VBASE + GIC_V2MTYPER_OFFSET) +#define GIC_V2MSETSPI (MPCORE_V2M_VBASE + GIC_V2MSETSPI_OFFSET) + /* GIC Register Bit Definitions *********************************************/ /* CPU Interface registers */ @@ -557,6 +567,14 @@ # define GIC_ICDSGIR_TGTFILTER_THIS (2 << GIC_ICDSGIR_TGTFILTER_SHIFT) /* Interrupt is sent to requesting CPU only */ /* Bits 26-31: Reserved */ +/* V2M Registers */ + +#define GIC_V2MTYPES_BASE_SHIFT 16 +#define GIC_V2MTYPES_BASE_MASK 0x3FF +#define GIC_V2MTYPES_NUMBER_MASK 0x3FF +#define GIC_V2MTYPES_BASE(x) (((x) >> GIC_V2MTYPES_BASE_SHIFT) & GIC_V2MTYPES_BASE_MASK) +#define GIC_V2MTYPES_NUMBER(x) ((x) & GIC_V2MTYPES_NUMBER_MASK) + /* Interrupt IDs ************************************************************/ /* The Global Interrupt Controller (GIC) collects up to 224 interrupt @@ -886,6 +904,10 @@ void arm_gic_dump(const char *msg, bool all, int irq); # define arm_gic_dump(msg, all, irq) #endif +#ifdef CONFIG_ARMV7A_GICv2M +int gic_v2m_initialize(void); +#endif + #undef EXTERN #ifdef __cplusplus } diff --git a/arch/arm/src/armv7-a/mpcore.h b/arch/arm/src/armv7-a/mpcore.h index 404c17dc75..524b9439c5 100644 --- a/arch/arm/src/armv7-a/mpcore.h +++ b/arch/arm/src/armv7-a/mpcore.h @@ -73,5 +73,6 @@ #define MPCORE_GTM_VBASE (CHIP_MPCORE_VBASE+MPCORE_GTM_OFFSET) #define MPCORE_PTM_VBASE (CHIP_MPCORE_VBASE+MPCORE_PTM_OFFSET) #define MPCORE_ICD_VBASE (CHIP_MPCORE_VBASE+MPCORE_ICD_OFFSET) +#define MPCORE_V2M_VBASE (CHIP_MPCORE_VBASE+MPCORE_V2M_OFFSET) #endif /* __ARCH_ARM_SRC_ARMV7_A_MPCORE_H */ diff --git a/arch/arm/src/qemu/chip.h b/arch/arm/src/qemu/chip.h index ab2ccc38fa..e3eb6a816e 100644 --- a/arch/arm/src/qemu/chip.h +++ b/arch/arm/src/qemu/chip.h @@ -35,6 +35,7 @@ #define CHIP_MPCORE_VBASE 0x8000000 #define MPCORE_ICD_OFFSET 0x0000 #define MPCORE_ICC_OFFSET 0x10000 +#define MPCORE_V2M_OFFSET 0x20000 #define PGTABLE_SIZE 0x00004000 #define PGTABLE_BASE_PADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - PGTABLE_SIZE * CONFIG_SMP_NCPUS) diff --git a/drivers/pci/pci_ecam.c b/drivers/pci/pci_ecam.c index f238bb4eee..111baa20c4 100644 --- a/drivers/pci/pci_ecam.c +++ b/drivers/pci/pci_ecam.c @@ -24,6 +24,7 @@ #include +#include #include #include #include @@ -61,6 +62,21 @@ static int pci_ecam_read_io(FAR struct pci_bus_s *bus, uintptr_t addr, static int pci_ecam_write_io(FAR struct pci_bus_s *bus, uintptr_t addr, int size, uint32_t val); +static int pci_ecam_get_irq(FAR struct pci_bus_s *bus, uint32_t devfn, + uint8_t line, uint8_t pin); + +#ifdef CONFIG_PCI_MSIX +static int pci_ecam_alloc_irq(FAR struct pci_bus_s *bus, FAR int *irq, + int num); + +static void pci_ecam_release_irq(FAR struct pci_bus_s *bus, FAR int *irq, + int num); + +static int pci_ecam_connect_irq(FAR struct pci_bus_s *bus, FAR int *irq, + int num, FAR uintptr_t *mar, + FAR uint32_t *mdr); +#endif + /**************************************************************************** * Private Types ****************************************************************************/ @@ -77,10 +93,16 @@ struct pci_ecam_s static const struct pci_ops_s g_pci_ecam_ops = { - .read = pci_ecam_read_config, - .write = pci_ecam_write_config, - .read_io = pci_ecam_read_io, - .write_io = pci_ecam_write_io, + .read = pci_ecam_read_config, + .write = pci_ecam_write_config, + .read_io = pci_ecam_read_io, + .write_io = pci_ecam_write_io, + .get_irq = pci_ecam_get_irq, +#ifdef CONFIG_PCI_MSIX + .alloc_irq = pci_ecam_alloc_irq, + .release_irq = pci_ecam_release_irq, + .connect_irq = pci_ecam_connect_irq, +#endif }; /**************************************************************************** @@ -368,6 +390,53 @@ static int pci_ecam_write_io(FAR struct pci_bus_s *bus, uintptr_t addr, return OK; } +#ifdef CONFIG_PCI_MSIX +static int pci_ecam_alloc_irq(FAR struct pci_bus_s *bus, FAR int *irq, + int num) +{ + *irq = up_alloc_irq_msi(&num); + return num; +} + +static void pci_ecam_release_irq(FAR struct pci_bus_s *bus, FAR int *irq, + int num) +{ + return up_release_irq_msi(irq, num); +} + +static int pci_ecam_connect_irq(FAR struct pci_bus_s *bus, FAR int *irq, + int num, FAR uintptr_t *mar, + FAR uint32_t *mdr) +{ + return up_connect_irq(irq, num, mar, mdr); +} +#endif + +/**************************************************************************** + * Name: pci_ecam_get_irq + * + * Description: + * Get interrupt number associated with a given INTx line. + * + * Input Parameters: + * bus - Bus that PCI device resides + * devfn - The pci device and function number + * line - Activated PCI legacy interrupt line + * pin - Intx pin number + * + * Returned Value: + * Return interrupt number associated with a given INTx + * + ****************************************************************************/ + +static int pci_ecam_get_irq(FAR struct pci_bus_s *bus, uint32_t devfn, + uint8_t line, uint8_t pin) +{ + UNUSED(bus); + + return up_get_legacy_irq(devfn, line, pin); +} + /**************************************************************************** * Public Functions ****************************************************************************/