diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 5355534f3d..cf6af68299 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -134,6 +134,14 @@ config GICV3 Driver for the ARM Generic Interrupt Controller v3. If unsure, use the default setting. +config GICV3_ESPI + bool "Extended SPI range support" + depends on GICV3 && !NEW_VGIC + help + Allow Xen and domains to use interrupt numbers from the extended SPI + range, from 4096 to 5119. This feature is introduced in GICv3.1 + architecture. + config HAS_ITS bool "GICv3 ITS MSI controller support (UNSUPPORTED)" if UNSUPPORTED depends on GICV3 && !NEW_VGIC && !ARM_32 diff --git a/xen/arch/arm/include/asm/irq.h b/xen/arch/arm/include/asm/irq.h index 5bc6475eb4..09788dbfeb 100644 --- a/xen/arch/arm/include/asm/irq.h +++ b/xen/arch/arm/include/asm/irq.h @@ -32,6 +32,10 @@ struct arch_irq_desc { #define SPI_MAX_INTID 1019 #define LPI_OFFSET 8192 +#define ESPI_BASE_INTID 4096 +#define ESPI_MAX_INTID 5119 +#define NR_ESPI_IRQS 1024 + /* LPIs are always numbered starting at 8192, so 0 is a good invalid case. */ #define INVALID_LPI 0 @@ -39,7 +43,12 @@ struct arch_irq_desc { #define INVALID_IRQ 1023 extern const unsigned int nr_irqs; +#ifdef CONFIG_GICV3_ESPI +/* This will cover the eSPI range, to allow assignment of eSPIs to domains. */ +#define nr_static_irqs (ESPI_MAX_INTID + 1) +#else #define nr_static_irqs NR_IRQS +#endif struct irq_desc; struct irqaction; @@ -55,6 +64,34 @@ static inline bool is_lpi(unsigned int irq) return irq >= LPI_OFFSET; } +static inline bool is_espi(unsigned int irq) +{ +#ifdef CONFIG_GICV3_ESPI + return irq >= ESPI_BASE_INTID && irq <= ESPI_MAX_INTID; +#else + /* + * The function should not be called for eSPIs when CONFIG_GICV3_ESPI is + * disabled. Returning false allows the compiler to optimize the code + * when the config is disabled, while the assert ensures that out-of-range + * array resources are not accessed. + */ + ASSERT(!(irq >= ESPI_BASE_INTID && irq <= ESPI_MAX_INTID)); + return false; +#endif +} + +static inline unsigned int espi_intid_to_idx(unsigned int intid) +{ + ASSERT(is_espi(intid)); + return intid - ESPI_BASE_INTID; +} + +static inline unsigned int espi_idx_to_intid(unsigned int idx) +{ + ASSERT(idx <= NR_ESPI_IRQS); + return idx + ESPI_BASE_INTID; +} + #define domain_pirq_to_irq(d, pirq) (pirq) bool is_assignable_irq(unsigned int irq); diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index 0df1e0a7c1..53f5f4612f 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -19,7 +19,9 @@ #include #include -const unsigned int nr_irqs = NR_IRQS; +const unsigned int nr_irqs = IS_ENABLED(CONFIG_GICV3_ESPI) ? + (ESPI_MAX_INTID + 1) : + NR_IRQS; static unsigned int local_irqs_type[NR_LOCAL_IRQS]; static DEFINE_SPINLOCK(local_irqs_type_lock); @@ -46,6 +48,41 @@ void irq_end_none(struct irq_desc *irq) } static irq_desc_t irq_desc[NR_IRQS - NR_LOCAL_IRQS]; +#ifdef CONFIG_GICV3_ESPI +/* TODO: Consider allocating an array dynamically */ +static irq_desc_t espi_desc[NR_ESPI_IRQS]; + +static struct irq_desc *espi_to_desc(unsigned int irq) +{ + return &espi_desc[espi_intid_to_idx(irq)]; +} + +static int __init init_espi_data(void) +{ + unsigned int irq; + + for ( irq = ESPI_BASE_INTID; irq <= ESPI_MAX_INTID; irq++ ) + { + struct irq_desc *desc = irq_to_desc(irq); + int rc = init_one_irq_desc(desc); + + if ( rc ) + return rc; + + desc->irq = irq; + desc->action = NULL; + } + + return 0; +} +#else + +static int __init init_espi_data(void) +{ + return 0; +} +#endif + static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc); struct irq_desc *__irq_to_desc(unsigned int irq) @@ -53,6 +90,11 @@ struct irq_desc *__irq_to_desc(unsigned int irq) if ( irq < NR_LOCAL_IRQS ) return &this_cpu(local_irq_desc)[irq]; +#ifdef CONFIG_GICV3_ESPI + if ( is_espi(irq) ) + return espi_to_desc(irq); +#endif + return &irq_desc[irq-NR_LOCAL_IRQS]; } @@ -79,7 +121,7 @@ static int __init init_irq_data(void) desc->action = NULL; } - return 0; + return init_espi_data(); } static int init_local_irq_data(unsigned int cpu)