acrn-hypervisor/hypervisor/common/irq.c
Geoffroy Van Cutsem 8b16be9185 Remove "All rights reserved" string headers
Many of the license and Intel copyright headers include the "All rights
reserved" string. It is not relevant in the context of the BSD-3-Clause
license that the code is released under. This patch removes those strings
throughout the code (hypervisor, devicemodel and misc).

Tracked-On: #7254
Signed-off-by: Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com>
2022-04-06 13:21:02 +08:00

232 lines
5.4 KiB
C

/*
* Copyright (C) 2021 Intel Corporation.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <asm/lib/bits.h>
#include <irq.h>
#include <common/softirq.h>
#include <asm/irq.h>
#include <asm/per_cpu.h>
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_ON_CONFIG();
}