mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-31 07:20:55 +00:00
hv: pirq: refactor vector allocation/free
This commit refactors vector allocation/free codes, two functions are defined to help alloc/free vectors for an irq: - uint32_t alloc_irq_vector(uint32_t irq) - alloc a free vector (0x20 ~ 0xDF), and bind it to irq, for legacy irqs and static mapped irqs, vector has been allocated and bind, so just check the mapping correctness; - return: valid vector on success, VECTOR_INVALID on failure. - void free_irq_vector(uint32_t irq) - free vector allocated via alloc_irq_vector(), for legacy irqs and static mapped irqs, nothing need to do. Signed-off-by: Yan, Like <like.yan@intel.com> Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
parent
1bf2fc342a
commit
2c044e0c4e
@ -371,8 +371,8 @@ void setup_ioapic_irq(void)
|
|||||||
* for legacy irq, reserved vector and never free
|
* for legacy irq, reserved vector and never free
|
||||||
*/
|
*/
|
||||||
if (gsi < NR_LEGACY_IRQ) {
|
if (gsi < NR_LEGACY_IRQ) {
|
||||||
vr = irq_desc_alloc_vector(gsi);
|
vr = alloc_irq_vector(gsi);
|
||||||
if (vr > NR_MAX_VECTOR) {
|
if (vr == VECTOR_INVALID) {
|
||||||
pr_err("failed to alloc VR");
|
pr_err("failed to alloc VR");
|
||||||
gsi++;
|
gsi++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -46,22 +46,6 @@ static void init_irq_desc(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* find available vector VECTOR_DYNAMIC_START ~ VECTOR_DYNAMIC_END
|
|
||||||
*/
|
|
||||||
static uint32_t find_available_vector()
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
/* TODO: vector lock required */
|
|
||||||
for (i = VECTOR_DYNAMIC_START; i <= VECTOR_DYNAMIC_END; i++) {
|
|
||||||
if (vector_to_irq[i] == IRQ_INVALID) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return VECTOR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* alloc an free irq if req_irq is IRQ_INVALID, or else set assigned
|
* alloc an free irq if req_irq is IRQ_INVALID, or else set assigned
|
||||||
* return: irq num on success, IRQ_INVALID on failure
|
* return: irq num on success, IRQ_INVALID on failure
|
||||||
@ -119,35 +103,62 @@ void free_irq_num(uint32_t irq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* need lock protection before use */
|
/*
|
||||||
static void local_irq_desc_set_vector(uint32_t irq, uint32_t vr)
|
* alloc an vectror and bind it to irq
|
||||||
|
* for legacy_irq (irq num < 16) and static mapped ones, do nothing
|
||||||
|
* if mapping is correct.
|
||||||
|
* retval: valid vector num on susccess, VECTOR_INVALID on failure.
|
||||||
|
*/
|
||||||
|
uint32_t alloc_irq_vector(uint32_t irq)
|
||||||
{
|
{
|
||||||
|
uint32_t vr;
|
||||||
struct irq_desc *desc;
|
struct irq_desc *desc;
|
||||||
|
|
||||||
desc = &irq_desc_array[irq];
|
|
||||||
vector_to_irq[vr] = irq;
|
|
||||||
desc->vector = vr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lock version of set vector */
|
|
||||||
static void irq_desc_set_vector(uint32_t irq, uint32_t vr)
|
|
||||||
{
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
struct irq_desc *desc;
|
|
||||||
|
if (irq >= NR_IRQS) {
|
||||||
|
pr_err("invalid irq[%u] to alloc vector", irq);
|
||||||
|
return VECTOR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
desc = &irq_desc_array[irq];
|
desc = &irq_desc_array[irq];
|
||||||
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
|
||||||
vector_to_irq[vr] = irq;
|
if (desc->vector != VECTOR_INVALID) {
|
||||||
desc->vector = vr;
|
if (vector_to_irq[desc->vector] == irq) {
|
||||||
spinlock_irqrestore_release(&desc->lock, rflags);
|
/* statically binded */
|
||||||
|
vr = desc->vector;
|
||||||
|
} else {
|
||||||
|
pr_err("[%s] irq[%u]:vector[%u] mismatch",
|
||||||
|
__func__, irq, desc->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) {
|
||||||
|
desc->vector = vr;
|
||||||
|
vector_to_irq[vr] = irq;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vr = (vr > VECTOR_DYNAMIC_END) ? VECTOR_INVALID : vr;
|
||||||
|
|
||||||
|
spinlock_irqrestore_release(&irq_alloc_spinlock, rflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* used with holding lock outside */
|
/* free the vector allocated via alloc_irq_vector() */
|
||||||
static void _irq_desc_free_vector(uint32_t irq)
|
void free_irq_vector(uint32_t irq)
|
||||||
{
|
{
|
||||||
struct irq_desc *desc;
|
struct irq_desc *desc;
|
||||||
uint32_t vr;
|
uint32_t vr;
|
||||||
uint16_t pcpu_id;
|
uint64_t rflags;
|
||||||
|
|
||||||
if (irq >= NR_IRQS) {
|
if (irq >= NR_IRQS) {
|
||||||
return;
|
return;
|
||||||
@ -155,18 +166,20 @@ static void _irq_desc_free_vector(uint32_t irq)
|
|||||||
|
|
||||||
desc = &irq_desc_array[irq];
|
desc = &irq_desc_array[irq];
|
||||||
|
|
||||||
|
if ((irq < NR_LEGACY_IRQ) || (desc->vector >= VECTOR_FIXED_START)) {
|
||||||
|
/* do nothing for LEGACY_IRQ and static allocated ones */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags);
|
||||||
vr = desc->vector;
|
vr = desc->vector;
|
||||||
desc->used = IRQ_NOT_ASSIGNED;
|
|
||||||
desc->vector = VECTOR_INVALID;
|
desc->vector = VECTOR_INVALID;
|
||||||
|
|
||||||
vr &= NR_MAX_VECTOR;
|
vr &= NR_MAX_VECTOR;
|
||||||
if (vector_to_irq[vr] == irq) {
|
if (vector_to_irq[vr] == irq) {
|
||||||
vector_to_irq[vr] = IRQ_INVALID;
|
vector_to_irq[vr] = IRQ_INVALID;
|
||||||
}
|
}
|
||||||
|
spinlock_irqrestore_release(&irq_alloc_spinlock, rflags);
|
||||||
for (pcpu_id = 0U; pcpu_id < phys_cpu_num; pcpu_id++) {
|
|
||||||
per_cpu(irq_count, pcpu_id)[irq] = 0UL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_pic_irq(void)
|
static void disable_pic_irq(void)
|
||||||
@ -175,6 +188,28 @@ static void disable_pic_irq(void)
|
|||||||
pio_write8(0xffU, 0x21U);
|
pio_write8(0xffU, 0x21U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,
|
int32_t request_irq(uint32_t req_irq,
|
||||||
irq_action_t action_fn,
|
irq_action_t action_fn,
|
||||||
void *priv_data)
|
void *priv_data)
|
||||||
@ -183,65 +218,32 @@ int32_t request_irq(uint32_t req_irq,
|
|||||||
uint32_t irq, vector;
|
uint32_t irq, vector;
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
|
|
||||||
/* ======================================================
|
|
||||||
* This is low level ISR handler registering function
|
|
||||||
* case: 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
|
|
||||||
* a irq will be allocated and the vector will be assigned to this
|
|
||||||
* irq automatically.
|
|
||||||
*
|
|
||||||
* case: irq >=0 and irq < nr_gsi
|
|
||||||
* caller want to add device ISR handler into ioapic pins.
|
|
||||||
* two kind of devices: legacy device and PCI device with INTx
|
|
||||||
* a vector will automatically assigned.
|
|
||||||
*
|
|
||||||
* case: irq with speical type (not from IOAPIC/MSI)
|
|
||||||
* These irq value are pre-defined for Timer, IPI, Spurious etc
|
|
||||||
* vectors are pre-defined also
|
|
||||||
*
|
|
||||||
* return value: pinned irq and assigned vector for this irq.
|
|
||||||
* caller can use this irq to enable/disable/mask/unmask interrupt
|
|
||||||
* and if this irq is for:
|
|
||||||
* GSI legacy: nothing to do for legacy irq, already initialized
|
|
||||||
* GSI other: need to progam PCI INTx to match this irq pin
|
|
||||||
* MSI: caller need program vector to PCI device
|
|
||||||
*
|
|
||||||
* =====================================================
|
|
||||||
*/
|
|
||||||
irq = alloc_irq_num(req_irq);
|
irq = alloc_irq_num(req_irq);
|
||||||
if (irq == IRQ_INVALID) {
|
if (irq == IRQ_INVALID) {
|
||||||
pr_err("[%s] invalid irq num", __func__);
|
pr_err("[%s] invalid irq num", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
desc = &irq_desc_array[irq];
|
vector = alloc_irq_vector(irq);
|
||||||
if (desc->irq_handler == NULL) {
|
if (vector == VECTOR_INVALID) {
|
||||||
desc->irq_handler = common_handler_edge;
|
pr_err("[%s] failed to alloc vector for irq %u",
|
||||||
}
|
__func__, irq);
|
||||||
|
|
||||||
vector = desc->vector;
|
|
||||||
if (vector >= VECTOR_FIXED_START &&
|
|
||||||
vector <= VECTOR_FIXED_END) {
|
|
||||||
irq_desc_set_vector(irq, vector);
|
|
||||||
} else if (vector > NR_MAX_VECTOR) {
|
|
||||||
irq_desc_alloc_vector(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (desc->vector == VECTOR_INVALID) {
|
|
||||||
pr_err("the input vector is not correct");
|
|
||||||
free_irq_num(irq);
|
free_irq_num(irq);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
desc = &irq_desc_array[irq];
|
||||||
|
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
||||||
|
if (desc->irq_handler == NULL) {
|
||||||
|
desc->irq_handler = common_handler_edge;
|
||||||
|
}
|
||||||
|
|
||||||
if (desc->action == NULL) {
|
if (desc->action == NULL) {
|
||||||
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
|
||||||
desc->priv_data = priv_data;
|
desc->priv_data = priv_data;
|
||||||
desc->action = action_fn;
|
desc->action = action_fn;
|
||||||
|
|
||||||
spinlock_irqrestore_release(&desc->lock, rflags);
|
spinlock_irqrestore_release(&desc->lock, rflags);
|
||||||
} else {
|
} else {
|
||||||
|
spinlock_irqrestore_release(&desc->lock, rflags);
|
||||||
pr_err("%s: request irq(%u) vr(%u) failed,\
|
pr_err("%s: request irq(%u) vr(%u) failed,\
|
||||||
already requested", __func__,
|
already requested", __func__,
|
||||||
irq, irq_to_vector(irq));
|
irq, irq_to_vector(irq));
|
||||||
@ -254,58 +256,6 @@ int32_t request_irq(uint32_t req_irq,
|
|||||||
return (int32_t)irq;
|
return (int32_t)irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* it is safe to call irq_desc_alloc_vector multiple times*/
|
|
||||||
uint32_t irq_desc_alloc_vector(uint32_t irq)
|
|
||||||
{
|
|
||||||
uint32_t vr = VECTOR_INVALID;
|
|
||||||
uint64_t rflags;
|
|
||||||
struct irq_desc *desc;
|
|
||||||
|
|
||||||
|
|
||||||
/* irq should be always available at this time */
|
|
||||||
if (irq >= NR_IRQS) {
|
|
||||||
return VECTOR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc = &irq_desc_array[irq];
|
|
||||||
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
|
||||||
if (desc->vector != VECTOR_INVALID) {
|
|
||||||
/* already allocated a vector */
|
|
||||||
goto OUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FLAT mode, a irq connected to every cpu's same vector */
|
|
||||||
vr = find_available_vector();
|
|
||||||
if (vr > NR_MAX_VECTOR) {
|
|
||||||
pr_err("no vector found for irq[%d]", irq);
|
|
||||||
goto OUT;
|
|
||||||
}
|
|
||||||
local_irq_desc_set_vector(irq, vr);
|
|
||||||
OUT:
|
|
||||||
spinlock_irqrestore_release(&desc->lock, rflags);
|
|
||||||
return vr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void irq_desc_try_free_vector(uint32_t irq)
|
|
||||||
{
|
|
||||||
uint64_t rflags;
|
|
||||||
struct irq_desc *desc;
|
|
||||||
|
|
||||||
/* legacy irq's vector is reserved and should not be freed */
|
|
||||||
if ((irq >= NR_IRQS) || (irq < NR_LEGACY_IRQ)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc = &irq_desc_array[irq];
|
|
||||||
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
|
||||||
if (desc->action == NULL) {
|
|
||||||
_irq_desc_free_vector(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
spinlock_irqrestore_release(&desc->lock, rflags);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t irq_to_vector(uint32_t irq)
|
uint32_t irq_to_vector(uint32_t irq)
|
||||||
{
|
{
|
||||||
if (irq < NR_IRQS) {
|
if (irq < NR_IRQS) {
|
||||||
@ -527,14 +477,13 @@ void free_irq(uint32_t irq)
|
|||||||
dev_dbg(ACRN_DBG_IRQ, "[%s] irq%d vr:0x%x",
|
dev_dbg(ACRN_DBG_IRQ, "[%s] irq%d vr:0x%x",
|
||||||
__func__, irq, irq_to_vector(irq));
|
__func__, irq, irq_to_vector(irq));
|
||||||
|
|
||||||
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
free_irq_vector(irq);
|
||||||
|
free_irq_num(irq);
|
||||||
|
|
||||||
|
spinlock_irqsave_obtain(&desc->lock, &rflags);
|
||||||
desc->action = NULL;
|
desc->action = NULL;
|
||||||
desc->priv_data = NULL;
|
desc->priv_data = NULL;
|
||||||
|
|
||||||
spinlock_irqrestore_release(&desc->lock, rflags);
|
spinlock_irqrestore_release(&desc->lock, rflags);
|
||||||
irq_desc_try_free_vector(desc->irq);
|
|
||||||
free_irq_num(irq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HV_DEBUG
|
#ifdef HV_DEBUG
|
||||||
|
@ -75,6 +75,9 @@ typedef void (*spurious_handler_t)(uint32_t vector);
|
|||||||
extern spurious_handler_t spurious_handler;
|
extern spurious_handler_t spurious_handler;
|
||||||
|
|
||||||
uint32_t alloc_irq_num(uint32_t req_irq);
|
uint32_t alloc_irq_num(uint32_t req_irq);
|
||||||
|
uint32_t alloc_irq_vector(uint32_t irq);
|
||||||
|
|
||||||
|
uint32_t irq_to_vector(uint32_t irq);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some MSI message definitions
|
* Some MSI message definitions
|
||||||
|
@ -34,11 +34,6 @@ struct irq_desc {
|
|||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t irq_desc_alloc_vector(uint32_t irq);
|
|
||||||
void irq_desc_try_free_vector(uint32_t irq);
|
|
||||||
|
|
||||||
uint32_t irq_to_vector(uint32_t irq);
|
|
||||||
|
|
||||||
int32_t request_irq(uint32_t irq,
|
int32_t request_irq(uint32_t irq,
|
||||||
irq_action_t action_fn,
|
irq_action_t action_fn,
|
||||||
void *priv_data);
|
void *priv_data);
|
||||||
|
Loading…
Reference in New Issue
Block a user