From 3a50f949e1d2f0d88feb42bfb74c3a7753631001 Mon Sep 17 00:00:00 2001 From: Liang Yi Date: Tue, 16 Mar 2021 10:02:12 +0800 Subject: [PATCH] hv/mod_irq: split irq.c into arch/x86/irq.c and common/irq.c The common irq file is responsible for managing the central irq_desc data structure and provides the following APIs for host interrupt handling. - init_interrupt() - reserve_irq_num() - request_irq() - free_irq() - set_irq_trigger_mode() - do_irq() API prototypes, constant and data structures belonging to common interrupt handling are all moved into include/common/irq.h. Conversely, the following arch specific APIs are added which are called from the common code at various points: - init_irq_descs_arch() - setup_irqs_arch() - init_interrupt_arch() - free_irq_arch() - request_irq_arch() - pre_irq_arch() - post_irq_arch() Tracked-On: #5825 Signed-off-by: Peter Fang Reviewed-by: Jason Chen CJ --- hypervisor/Makefile | 1 + hypervisor/arch/x86/irq.c | 271 ++++-------------------------- hypervisor/common/irq.c | 230 +++++++++++++++++++++++++ hypervisor/include/arch/x86/irq.h | 158 ++++------------- hypervisor/include/common/irq.h | 136 +++++++++++++++ 5 files changed, 432 insertions(+), 364 deletions(-) create mode 100644 hypervisor/common/irq.c create mode 100644 hypervisor/include/common/irq.h diff --git a/hypervisor/Makefile b/hypervisor/Makefile index ee909cca6..b6d663a29 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -225,6 +225,7 @@ HW_C_SRCS += arch/x86/trampoline.c HW_S_SRCS += arch/x86/sched.S HW_C_SRCS += arch/x86/rdt.c HW_C_SRCS += arch/x86/sgx.c +HW_C_SRCS += common/irq.c HW_C_SRCS += common/softirq.c HW_C_SRCS += common/schedule.c HW_C_SRCS += common/event.c diff --git a/hypervisor/arch/x86/irq.c b/hypervisor/arch/x86/irq.c index ae32c1113..f9e79280a 100644 --- a/hypervisor/arch/x86/irq.c +++ b/hypervisor/arch/x86/irq.c @@ -19,15 +19,14 @@ #include #include -static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, }; +static spinlock_t x86_irq_spinlock = { .head = 0U, .tail = 0U, }; -uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; -struct irq_desc irq_desc_array[NR_IRQS]; static struct x86_irq_data irq_data[NR_IRQS]; -static uint64_t irq_rsvd_bitmap[IRQ_ALLOC_BITMAP_SIZE]; static uint32_t vector_to_irq[NR_MAX_VECTOR + 1]; +typedef void (*spurious_handler_t)(uint32_t vector); + spurious_handler_t spurious_handler; static struct { @@ -42,67 +41,6 @@ static struct { [NR_STATIC_MAPPINGS_1 ... (NR_STATIC_MAPPINGS - 1U)] = {}, }; -/* - * alloc an free irq if req_irq is IRQ_INVALID, or else set assigned - * return: irq num on success, IRQ_INVALID on failure - */ -static uint32_t alloc_irq_num(uint32_t req_irq, bool reserve) -{ - uint32_t irq = req_irq; - uint64_t rflags; - uint32_t ret; - - if ((irq >= NR_IRQS) && (irq != IRQ_INVALID)) { - pr_err("[%s] invalid req_irq %u", __func__, req_irq); - ret = IRQ_INVALID; - } else { - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); - if (irq == IRQ_INVALID) { - /* if no valid irq num given, find a free one */ - irq = (uint32_t)ffz64_ex(irq_alloc_bitmap, NR_IRQS); - } - - if (irq >= NR_IRQS) { - irq = IRQ_INVALID; - } else { - bitmap_set_nolock((uint16_t)(irq & 0x3FU), - irq_alloc_bitmap + (irq >> 6U)); - if (reserve) { - bitmap_set_nolock((uint16_t)(irq & 0x3FU), - irq_rsvd_bitmap + (irq >> 6U)); - } - } - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); - ret = irq; - } - return ret; -} - -uint32_t reserve_irq_num(uint32_t irq) -{ - return alloc_irq_num(irq, true); -} - -/* - * @pre: irq is not in irq_static_mappings - * free irq num allocated via alloc_irq_num() - */ -static void free_irq_num(uint32_t irq) -{ - uint64_t rflags; - - if (irq < NR_IRQS) { - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); - - if (bitmap_test((uint16_t)(irq & 0x3FU), - irq_rsvd_bitmap + (irq >> 6U)) == false) { - bitmap_clear_nolock((uint16_t)(irq & 0x3FU), - irq_alloc_bitmap + (irq >> 6U)); - } - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); - } -} - /* * alloc an vectror and bind it to irq * for legacy_irq (irq num < 16) and static mapped ones, do nothing @@ -111,13 +49,14 @@ static void free_irq_num(uint32_t irq) */ uint32_t alloc_irq_vector(uint32_t irq) { - uint32_t vr; struct x86_irq_data *irqd; uint64_t rflags; - uint32_t ret; + uint32_t vr = VECTOR_INVALID; + uint32_t ret = VECTOR_INVALID; if (irq < NR_IRQS) { irqd = &irq_data[irq]; + spinlock_irqsave_obtain(&x86_irq_spinlock, &rflags); if (irqd->vector != VECTOR_INVALID) { if (vector_to_irq[irqd->vector] == irq) { @@ -126,14 +65,11 @@ uint32_t alloc_irq_vector(uint32_t irq) } else { pr_err("[%s] irq[%u]:vector[%u] mismatch", __func__, irq, irqd->vector); - vr = VECTOR_INVALID; } } else { /* alloc a vector between: * VECTOR_DYNAMIC_START ~ VECTOR_DYNAMC_END */ - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); - for (vr = VECTOR_DYNAMIC_START; vr <= VECTOR_DYNAMIC_END; vr++) { if (vector_to_irq[vr] == IRQ_INVALID) { @@ -143,17 +79,21 @@ uint32_t alloc_irq_vector(uint32_t irq) } } vr = (vr > VECTOR_DYNAMIC_END) ? VECTOR_INVALID : vr; - - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); } + spinlock_irqrestore_release(&x86_irq_spinlock, rflags); ret = vr; } else { pr_err("invalid irq[%u] to alloc vector", irq); - ret = VECTOR_INVALID; } + return ret; } +bool request_irq_arch(uint32_t irq) +{ + return (alloc_irq_vector(irq) != VECTOR_INVALID); +} + /* free the vector allocated via alloc_irq_vector() */ static void free_irq_vector(uint32_t irq) { @@ -163,132 +103,35 @@ static void free_irq_vector(uint32_t irq) if (irq < NR_IRQS) { irqd = &irq_data[irq]; + spinlock_irqsave_obtain(&x86_irq_spinlock, &rflags); - if ((irq >= NR_LEGACY_IRQ) && (irqd->vector < VECTOR_FIXED_START)) { + if (irqd->vector < VECTOR_FIXED_START) { /* do nothing for LEGACY_IRQ and static allocated ones */ - - spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); vr = irqd->vector; irqd->vector = VECTOR_INVALID; - vr &= NR_MAX_VECTOR; - if (vector_to_irq[vr] == irq) { + if (vr <= NR_MAX_VECTOR && vector_to_irq[vr] == irq) { vector_to_irq[vr] = IRQ_INVALID; } - spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); } + spinlock_irqrestore_release(&x86_irq_spinlock, rflags); } } -/* - * There are four cases as to irq/vector allocation: - * case 1: req_irq = IRQ_INVALID - * caller did not know which irq to use, and want system to - * allocate available irq for it. These irq are in range: - * nr_gsi ~ NR_IRQS - * an irq will be allocated and a vector will be assigned to this - * irq automatically. - * case 2: req_irq >= NR_LAGACY_IRQ and irq < nr_gsi - * caller want to add device ISR handler into ioapic pins. - * a vector will automatically assigned. - * case 3: req_irq >=0 and req_irq < NR_LEGACY_IRQ - * caller want to add device ISR handler into ioapic pins, which - * is a legacy irq, vector already reserved. - * Nothing to do in this case. - * case 4: irq with speical type (not from IOAPIC/MSI) - * These irq value are pre-defined for Timer, IPI, Spurious etc, - * which is listed in irq_static_mappings[]. - * Nothing to do in this case. - * - * return value: valid irq (>=0) on success, otherwise errno (< 0). - */ -int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, - uint32_t flags) +void free_irq_arch(uint32_t irq) { - struct irq_desc *desc; - uint32_t irq, vector; - uint64_t rflags; - int32_t ret; - - irq = alloc_irq_num(req_irq, false); - if (irq == IRQ_INVALID) { - pr_err("[%s] invalid irq num", __func__); - ret = -EINVAL; - } else { - vector = alloc_irq_vector(irq); - - if (vector == VECTOR_INVALID) { - pr_err("[%s] failed to alloc vector for irq %u", - __func__, irq); - free_irq_num(irq); - ret = -EINVAL; - } else { - desc = &irq_desc_array[irq]; - if (desc->action == NULL) { - spinlock_irqsave_obtain(&desc->lock, &rflags); - desc->flags = flags; - desc->priv_data = priv_data; - desc->action = action_fn; - spinlock_irqrestore_release(&desc->lock, rflags); - - ret = (int32_t)irq; - dev_dbg(DBG_LEVEL_IRQ, "[%s] irq%d vr:0x%x", __func__, irq, vector); - } else { - ret = -EBUSY; - pr_err("%s: request irq(%u) vr(%u) failed, already requested", __func__, - irq, irq_to_vector(irq)); - } - } - } - - return ret; -} - -void free_irq(uint32_t irq) -{ - uint64_t rflags; - struct irq_desc *desc; - - if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - dev_dbg(DBG_LEVEL_IRQ, "[%s] irq%d vr:0x%x", - __func__, irq, irq_to_vector(irq)); - - free_irq_vector(irq); - free_irq_num(irq); - - spinlock_irqsave_obtain(&desc->lock, &rflags); - desc->action = NULL; - desc->priv_data = NULL; - desc->flags = IRQF_NONE; - spinlock_irqrestore_release(&desc->lock, rflags); - } -} - -void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered) -{ - uint64_t rflags; - struct irq_desc *desc; - - if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - spinlock_irqsave_obtain(&desc->lock, &rflags); - if (is_level_triggered) { - desc->flags |= IRQF_LEVEL; - } else { - desc->flags &= ~IRQF_LEVEL; - } - spinlock_irqrestore_release(&desc->lock, rflags); - } + free_irq_vector(irq); } uint32_t irq_to_vector(uint32_t irq) { - uint32_t ret; + uint64_t rflags; + uint32_t ret = VECTOR_INVALID; + if (irq < NR_IRQS) { + spinlock_irqsave_obtain(&x86_irq_spinlock, &rflags); ret = irq_data[irq].vector; - } else { - ret = VECTOR_INVALID; + spinlock_irqrestore_release(&x86_irq_spinlock, rflags); } return ret; @@ -322,7 +165,7 @@ static inline bool irq_need_unmask(const struct irq_desc *desc) && is_ioapic_irq(desc->irq)); } -static void pre_irq_arch(const struct irq_desc *desc) +void pre_irq_arch(const struct irq_desc *desc) { if (irq_need_mask(desc)) { ioapic_gsi_mask_irq(desc->irq); @@ -332,43 +175,13 @@ static void pre_irq_arch(const struct irq_desc *desc) send_lapic_eoi(); } -static void post_irq_arch(const struct irq_desc *desc) +void post_irq_arch(const struct irq_desc *desc) { if (irq_need_unmask(desc)) { ioapic_gsi_unmask_irq(desc->irq); } } -static inline void handle_irq(const struct irq_desc *desc) -{ - irq_action_t action = desc->action; - - pre_irq_arch(desc); - - if (action != NULL) { - action(desc->irq, desc->priv_data); - } - - post_irq_arch(desc); -} - -void do_irq(const uint32_t irq) -{ - struct irq_desc *desc; - - if (irq < NR_IRQS) { - desc = &irq_desc_array[irq]; - per_cpu(irq_count, get_pcpu_id())[irq]++; - - /* XXX irq_alloc_bitmap is used lockless here */ - if (bitmap_test((uint16_t)(irq & 0x3FU), irq_alloc_bitmap + (irq >> 6U))) { - handle_irq(desc); - } - } - - do_softirq(); -} - void dispatch_interrupt(const struct intr_excp_ctx *ctx) { uint32_t vr = ctx->vector; @@ -444,7 +257,7 @@ void handle_nmi(__unused struct intr_excp_ctx *ctx) exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32); } -static void init_irq_data_arch(struct irq_desc descs[]) +void init_irq_descs_arch(struct irq_desc descs[]) { uint32_t i; @@ -483,21 +296,8 @@ static void init_irq_data_arch(struct irq_desc descs[]) } } -static void init_irq_descs(void) -{ - uint32_t i; - - for (i = 0U; i < NR_IRQS; i++) { - struct irq_desc *desc = &irq_desc_array[i]; - desc->irq = i; - spinlock_init(&desc->lock); - } - - init_irq_data_arch(irq_desc_array); -} - /* must be called after IRQ setup */ -static void setup_irqs_arch(void) +void setup_irqs_arch(void) { ioapic_setup_irqs(); } @@ -531,7 +331,7 @@ static inline void set_idt(struct host_idt_descriptor *idtd) [idtd] "m"(*idtd)); } -static void init_interrupt_arch(uint16_t pcpu_id) +void init_interrupt_arch(uint16_t pcpu_id) { struct host_idt_descriptor *idtd = &HOST_IDTR; @@ -546,16 +346,3 @@ static void init_interrupt_arch(uint16_t pcpu_id) disable_pic_irqs(); } } - -void init_interrupt(uint16_t pcpu_id) -{ - init_interrupt_arch(pcpu_id); - - if (pcpu_id == BSP_CPU_ID) { - init_irq_descs(); - setup_irqs_arch(); - init_softirq(); - } - - CPU_IRQ_ENABLE(); -} diff --git a/hypervisor/common/irq.c b/hypervisor/common/irq.c new file mode 100644 index 000000000..3947ccdc6 --- /dev/null +++ b/hypervisor/common/irq.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2021 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, }; + +uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; +struct irq_desc irq_desc_array[NR_IRQS]; +static uint64_t irq_rsvd_bitmap[IRQ_ALLOC_BITMAP_SIZE]; + +/* + * alloc an free irq if req_irq is IRQ_INVALID, or else set assigned + * return: irq num on success, IRQ_INVALID on failure + */ +static uint32_t alloc_irq_num(uint32_t req_irq, bool reserve) +{ + uint32_t irq = req_irq; + uint64_t rflags; + uint32_t ret; + + if ((irq >= NR_IRQS) && (irq != IRQ_INVALID)) { + pr_err("[%s] invalid req_irq %u", __func__, req_irq); + ret = IRQ_INVALID; + } else { + spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); + if (irq == IRQ_INVALID) { + /* if no valid irq num given, find a free one */ + irq = (uint32_t)ffz64_ex(irq_alloc_bitmap, NR_IRQS); + } + + if (irq >= NR_IRQS) { + irq = IRQ_INVALID; + } else { + bitmap_set_nolock((uint16_t)(irq & 0x3FU), + irq_alloc_bitmap + (irq >> 6U)); + if (reserve) { + bitmap_set_nolock((uint16_t)(irq & 0x3FU), + irq_rsvd_bitmap + (irq >> 6U)); + } + } + spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); + ret = irq; + } + return ret; +} + +uint32_t reserve_irq_num(uint32_t irq) +{ + return alloc_irq_num(irq, true); +} + +/* + * @pre: irq is not in irq_static_mappings + * free irq num allocated via alloc_irq_num() + */ +static void free_irq_num(uint32_t irq) +{ + uint64_t rflags; + + if (irq < NR_IRQS) { + spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags); + + if (bitmap_test((uint16_t)(irq & 0x3FU), + irq_rsvd_bitmap + (irq >> 6U)) == false) { + bitmap_clear_nolock((uint16_t)(irq & 0x3FU), + irq_alloc_bitmap + (irq >> 6U)); + } + spinlock_irqrestore_release(&irq_alloc_spinlock, rflags); + } +} + +void free_irq(uint32_t irq) +{ + uint64_t rflags; + struct irq_desc *desc; + + if (irq < NR_IRQS) { + desc = &irq_desc_array[irq]; + + spinlock_irqsave_obtain(&desc->lock, &rflags); + desc->action = NULL; + desc->priv_data = NULL; + desc->flags = IRQF_NONE; + spinlock_irqrestore_release(&desc->lock, rflags); + + free_irq_arch(irq); + free_irq_num(irq); + } +} + +/* + * There are four cases as to irq/vector allocation: + * case 1: req_irq = IRQ_INVALID + * caller did not know which irq to use, and want system to + * allocate available irq for it. These irq are in range: + * nr_gsi ~ NR_IRQS + * an irq will be allocated and a vector will be assigned to this + * irq automatically. + * case 2: req_irq >= NR_LAGACY_IRQ and irq < nr_gsi + * caller want to add device ISR handler into ioapic pins. + * a vector will automatically assigned. + * case 3: req_irq >=0 and req_irq < NR_LEGACY_IRQ + * caller want to add device ISR handler into ioapic pins, which + * is a legacy irq, vector already reserved. + * Nothing to do in this case. + * case 4: irq with speical type (not from IOAPIC/MSI) + * These irq value are pre-defined for Timer, IPI, Spurious etc, + * which is listed in irq_static_mappings[]. + * Nothing to do in this case. + * + * return value: valid irq (>=0) on success, otherwise errno (< 0). + */ +int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, + uint32_t flags) +{ + struct irq_desc *desc; + uint32_t irq; + uint64_t rflags; + int32_t ret; + + irq = alloc_irq_num(req_irq, false); + if (irq == IRQ_INVALID) { + pr_err("[%s] invalid irq num", __func__); + ret = -EINVAL; + } else { + if (!request_irq_arch(irq)) { + pr_err("[%s] failed to alloc vector for irq %u", + __func__, irq); + free_irq_num(irq); + ret = -EINVAL; + } else { + desc = &irq_desc_array[irq]; + if (desc->action == NULL) { + spinlock_irqsave_obtain(&desc->lock, &rflags); + desc->flags = flags; + desc->priv_data = priv_data; + desc->action = action_fn; + spinlock_irqrestore_release(&desc->lock, rflags); + ret = (int32_t)irq; + } else { + ret = -EBUSY; + pr_err("%s: request irq(%u) failed, already requested", + __func__, irq); + } + } + } + + return ret; +} + +void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered) +{ + uint64_t rflags; + struct irq_desc *desc; + + if (irq < NR_IRQS) { + desc = &irq_desc_array[irq]; + spinlock_irqsave_obtain(&desc->lock, &rflags); + if (is_level_triggered) { + desc->flags |= IRQF_LEVEL; + } else { + desc->flags &= ~IRQF_LEVEL; + } + spinlock_irqrestore_release(&desc->lock, rflags); + } +} + +static inline void handle_irq(const struct irq_desc *desc) +{ + irq_action_t action = desc->action; + + pre_irq_arch(desc); + + if (action != NULL) { + action(desc->irq, desc->priv_data); + } + + post_irq_arch(desc); +} + +void do_irq(const uint32_t irq) +{ + struct irq_desc *desc; + + if (irq < NR_IRQS) { + desc = &irq_desc_array[irq]; + per_cpu(irq_count, get_pcpu_id())[irq]++; + + /* XXX irq_alloc_bitmap is used lockless here */ + if (bitmap_test((uint16_t)(irq & 0x3FU), irq_alloc_bitmap + (irq >> 6U))) { + handle_irq(desc); + } + } + + do_softirq(); +} + +static void init_irq_descs(void) +{ + uint32_t i; + + for (i = 0U; i < NR_IRQS; i++) { + struct irq_desc *desc = &irq_desc_array[i]; + desc->irq = i; + spinlock_init(&desc->lock); + } + + init_irq_descs_arch(irq_desc_array); +} + +void init_interrupt(uint16_t pcpu_id) +{ + init_interrupt_arch(pcpu_id); + + if (pcpu_id == BSP_CPU_ID) { + init_irq_descs(); + setup_irqs_arch(); + init_softirq(); + } + + CPU_IRQ_ENABLE(); +} diff --git a/hypervisor/include/arch/x86/irq.h b/hypervisor/include/arch/x86/irq.h index 26fbf20f2..f80f4e41a 100644 --- a/hypervisor/include/arch/x86/irq.h +++ b/hypervisor/include/arch/x86/irq.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef ARCH_IRQ_H -#define ARCH_IRQ_H +#ifndef ARCH_X86_IRQ_H +#define ARCH_X86_IRQ_H #include #include @@ -14,7 +14,7 @@ /** * @file arch/x86/irq.h * - * @brief public APIs for virtual IRQ + * @brief public APIs for x86 IRQ handling */ #define DBG_LEVEL_PTIRQ 6U @@ -22,8 +22,6 @@ #define NR_MAX_VECTOR 0xFFU #define VECTOR_INVALID (NR_MAX_VECTOR + 1U) -#define NR_IRQS 256U -#define IRQ_INVALID 0xffffffffU /* # of NR_STATIC_MAPPINGS_1 entries for timer, vcpu notify, and PMI */ #define NR_STATIC_MAPPINGS_1 3U @@ -82,13 +80,19 @@ #define DEFAULT_DEST_MODE IOAPIC_RTE_DESTMODE_LOGICAL #define DEFAULT_DELIVERY_MODE IOAPIC_RTE_DELMODE_LOPRI -#define IRQ_ALLOC_BITMAP_SIZE INT_DIV_ROUNDUP(NR_IRQS, 64U) - #define INVALID_INTERRUPT_PIN 0xffffffffU -#define IRQF_NONE (0U) -#define IRQF_LEVEL (1U << 1U) /* 1: level trigger; 0: edge trigger */ -#define IRQF_PT (1U << 2U) /* 1: for passthrough dev */ +/* + * x86 irq data + */ +struct x86_irq_data { + uint32_t vector; /**< assigned vector */ +#ifdef PROFILING_ON + uint64_t ctx_rip; + uint64_t ctx_rflags; + uint64_t ctx_cs; +#endif +}; struct acrn_vcpu; struct acrn_vm; @@ -116,18 +120,11 @@ struct smp_call_info_data { void smp_call_function(uint64_t mask, smp_call_func_t func, void *data); bool is_notification_nmi(const struct acrn_vm *vm); -void init_default_irqs(uint16_t cpu_id); - void dispatch_exception(struct intr_excp_ctx *ctx); void setup_notification(void); void setup_pi_notification(void); -typedef void (*spurious_handler_t)(uint32_t vector); -extern spurious_handler_t spurious_handler; - -uint32_t alloc_irq_vector(uint32_t irq); - /* RFLAGS */ #define HV_ARCH_VCPU_RFLAGS_TF (1UL<<8U) #define HV_ARCH_VCPU_RFLAGS_IF (1UL<<9U) @@ -242,99 +239,17 @@ int32_t interrupt_window_vmexit_handler(struct acrn_vcpu *vcpu); int32_t external_interrupt_vmexit_handler(struct acrn_vcpu *vcpu); int32_t acrn_handle_pending_request(struct acrn_vcpu *vcpu); -extern uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; - -typedef void (*irq_action_t)(uint32_t irq, void *priv_data); - -/* - * x86 irq data - */ -struct x86_irq_data { - uint32_t vector; /**< assigned vector */ -#ifdef PROFILING_ON - uint64_t ctx_rip; - uint64_t ctx_rflags; - uint64_t ctx_cs; -#endif -}; - /** - * @brief Interrupt descriptor + * @brief Allocate a vectror and bind it to irq * - * Any field change in below required lock protection with irqsave + * For legacy irq (num < 16) and statically mapped ones, do nothing + * if mapping is correct. + * + * @param[in] irq The irq num to bind + * + * @return valid vector num on susccess, VECTOR_INVALID on failure */ -struct irq_desc { - uint32_t irq; /**< index to irq_desc_base */ - - void *arch_data; /**< arch-specific data */ - - irq_action_t action; /**< callback registered from component */ - void *priv_data; /**< irq_action private data */ - uint32_t flags; /**< flags for trigger mode/ptdev */ - - spinlock_t lock; -}; - -/** - * @defgroup phys_int_ext_apis Physical Interrupt External Interfaces - * - * This is a group that includes Physical Interrupt External Interfaces. - * - * @{ - */ - -/** - * @brief Reserve an interrupt num - * - * Reserved interrupt num will not be available for dynamic IRQ allocations. - * This is normally used by the hypervisor for static IRQ mappings and/or - * arch specific, e.g. IOAPIC, interrupts during initialization. - * - * @param[in] req_irq irq_num to be reserved - * - * @retval >=0 on success, IRQ_INVALID on failure - */ -uint32_t reserve_irq_num(uint32_t req_irq); - -/** - * @brief Request an interrupt - * - * Request interrupt num if not specified, and register irq action for the - * specified/allocated irq. - * - * @param[in] req_irq irq_num to request, if IRQ_INVALID, a free irq - * number will be allocated - * @param[in] action_fn Function to be called when the IRQ occurs - * @param[in] priv_data Private data for action function. - * @param[in] flags Interrupt type flags, including: - * IRQF_NONE; - * IRQF_LEVEL - 1: level trigger; 0: edge trigger; - * IRQF_PT - 1: for passthrough dev - * - * @retval >=0 on success - * @retval IRQ_INVALID on failure - */ -int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, - uint32_t flags); - -/** - * @brief Free an interrupt - * - * Free irq num and unregister the irq action. - * - * @param[in] irq irq_num to be freed - */ -void free_irq(uint32_t irq); - -/** - * @brief Set interrupt trigger mode - * - * Set the irq trigger mode: edge-triggered or level-triggered - * - * @param[in] irq irq_num of interrupt to be set - * @param[in] is_level_triggered Trigger mode to set - */ -void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered); +uint32_t alloc_irq_vector(uint32_t irq); /** * @brief Get vector number of an interrupt from irq number @@ -363,22 +278,21 @@ void dispatch_interrupt(const struct intr_excp_ctx *ctx); */ void handle_nmi(__unused struct intr_excp_ctx *ctx); -/** - * @brief Initialize interrupt - * - * To do interrupt initialization for a cpu, will be called for each physical cpu. - * - * @param[in] pcpu_id The id of physical cpu to initialize - */ -void init_interrupt(uint16_t pcpu_id); - -/** - * @} - */ -/* End of phys_int_ext_apis */ - /** * @} */ /* End of acrn_virq */ -#endif /* ARCH_IRQ_H */ + +/* Arch specific routines called from generic IRQ handling */ + +struct irq_desc; + +void init_irq_descs_arch(struct irq_desc *descs); +void setup_irqs_arch(void); +void init_interrupt_arch(uint16_t pcpu_id); +void free_irq_arch(uint32_t irq); +bool request_irq_arch(uint32_t irq); +void pre_irq_arch(const struct irq_desc *desc); +void post_irq_arch(const struct irq_desc *desc); + +#endif /* ARCH_X86_IRQ_H */ diff --git a/hypervisor/include/common/irq.h b/hypervisor/include/common/irq.h new file mode 100644 index 000000000..bb8235879 --- /dev/null +++ b/hypervisor/include/common/irq.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef COMMON_IRQ_H +#define COMMON_IRQ_H + +#include +#include + +#include + +/** + * @file common/irq.h + * + * @brief public APIs for common IRQ handling + */ + +#define NR_IRQS 256U +#define IRQ_INVALID 0xffffffffU + +#define IRQ_ALLOC_BITMAP_SIZE INT_DIV_ROUNDUP(NR_IRQS, 64U) + +#define IRQF_NONE (0U) +#define IRQF_LEVEL (1U << 1U) /* 1: level trigger; 0: edge trigger */ +#define IRQF_PT (1U << 2U) /* 1: for passthrough dev */ + +extern uint64_t irq_alloc_bitmap[IRQ_ALLOC_BITMAP_SIZE]; + +typedef void (*irq_action_t)(uint32_t irq, void *priv_data); + +/** + * @brief Interrupt descriptor + * + * Any field change in below required lock protection with irqsave + */ +struct irq_desc { + uint32_t irq; /**< index to irq_desc_base */ + + void *arch_data; /**< arch-specific data */ + + irq_action_t action; /**< callback registered from component */ + void *priv_data; /**< irq_action private data */ + uint32_t flags; /**< flags for trigger mode/ptdev */ + + spinlock_t lock; +}; + +/** + * @defgroup phys_int_ext_apis Physical Interrupt External Interfaces + * + * This is a group that includes Physical Interrupt External Interfaces. + * + * @{ + */ + +/** + * @brief Reserve an interrupt num + * + * Reserved interrupt num will not be available for dynamic IRQ allocations. + * This is normally used by the hypervisor for static IRQ mappings and/or + * arch specific, e.g. IOAPIC, interrupts during initialization. + * + * @param[in] req_irq irq_num to be reserved + * + * @retval >=0 on success, IRQ_INVALID on failure + */ +uint32_t reserve_irq_num(uint32_t req_irq); + +/** + * @brief Request an interrupt + * + * Request interrupt num if not specified, and register irq action for the + * specified/allocated irq. + * + * @param[in] req_irq irq_num to request, if IRQ_INVALID, a free irq + * number will be allocated + * @param[in] action_fn Function to be called when the IRQ occurs + * @param[in] priv_data Private data for action function. + * @param[in] flags Interrupt type flags, including: + * IRQF_NONE; + * IRQF_LEVEL - 1: level trigger; 0: edge trigger; + * IRQF_PT - 1: for passthrough dev + * + * @retval >=0 on success + * @retval IRQ_INVALID on failure + */ +int32_t request_irq(uint32_t req_irq, irq_action_t action_fn, void *priv_data, + uint32_t flags); + +/** + * @brief Free an interrupt + * + * Free irq num and unregister the irq action. + * + * @param[in] irq irq_num to be freed + */ +void free_irq(uint32_t irq); + +/** + * @brief Set interrupt trigger mode + * + * Set the irq trigger mode: edge-triggered or level-triggered + * + * @param[in] irq irq_num of interrupt to be set + * @param[in] is_level_triggered Trigger mode to set + */ +void set_irq_trigger_mode(uint32_t irq, bool is_level_triggered); + +/** + * @brief Process an IRQ + * + * To process an IRQ, an action callback will be called if registered. + * + * @param irq irq_num to be processed + */ +void do_irq(const uint32_t irq); + +/** + * @brief Initialize interrupt + * + * To do interrupt initialization for a cpu, will be called for each physical cpu. + * + * @param[in] pcpu_id The id of physical cpu to initialize + */ +void init_interrupt(uint16_t pcpu_id); + + +/** + * @} + */ +/* End of phys_int_ext_apis */ + +#endif /* COMMON_IRQ_H */