hv: pirq: refactor irq num alloc/free

This commit refactors the alloc/free irq num, two functions are defined:
- uint32_t alloc_irq_num(uint32_t irq)
  - if irq is valid, mark the irq_desc as used; if it's IRQ_INVALID,
    alloc a free irq, or else do nothing;
  - return: irq num on success, or IRQ_INVALID on failure.

- void free_irq_num(uint32_t irq)
  - free the irq num allocated via alloc_irq_num();

And a global spinlock to protect it from concurrent allocation/free.

Signed-off-by: Yan, Like <like.yan@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Yan, Like 2018-08-16 16:50:57 +08:00 committed by lijinxia
parent f77d885d7e
commit 1bf2fc342a
4 changed files with 45 additions and 41 deletions

View File

@ -361,7 +361,7 @@ void setup_ioapic_irq(void)
} }
/* pinned irq before use it */ /* pinned irq before use it */
if (irq_mark_used(gsi) >= NR_IRQS) { if (alloc_irq_num(gsi) == IRQ_INVALID) {
pr_err("failed to alloc IRQ[%d]", gsi); pr_err("failed to alloc IRQ[%d]", gsi);
gsi++; gsi++;
continue; continue;

View File

@ -8,6 +8,7 @@
#include <softirq.h> #include <softirq.h>
static spinlock_t exception_spinlock = { .head = 0U, .tail = 0U, }; static spinlock_t exception_spinlock = { .head = 0U, .tail = 0U, };
static spinlock_t irq_alloc_spinlock = { .head = 0U, .tail = 0U, };
static struct irq_desc irq_desc_array[NR_IRQS]; static struct irq_desc irq_desc_array[NR_IRQS];
static uint32_t vector_to_irq[NR_MAX_VECTOR + 1]; static uint32_t vector_to_irq[NR_MAX_VECTOR + 1];
@ -62,49 +63,60 @@ static uint32_t find_available_vector()
} }
/* /*
* check and set irq to be assigned * alloc an free irq if req_irq is IRQ_INVALID, or else set assigned
* return: IRQ_INVALID if irq already assigned otherwise return irq * return: irq num on success, IRQ_INVALID on failure
*/ */
uint32_t irq_mark_used(uint32_t irq) uint32_t alloc_irq_num(uint32_t req_irq)
{ {
uint32_t i;
uint32_t irq = req_irq;
uint64_t rflags; uint64_t rflags;
struct irq_desc *desc; struct irq_desc *desc;
if (irq >= NR_IRQS) { if ((irq >= NR_IRQS) && (irq != IRQ_INVALID)) {
pr_err("[%s] invalid req_irq %u", __func__, req_irq);
return IRQ_INVALID; return IRQ_INVALID;
} }
desc = &irq_desc_array[irq]; spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags);
spinlock_irqsave_obtain(&desc->lock, &rflags); if (irq == IRQ_INVALID) {
if (desc->used == IRQ_NOT_ASSIGNED) { /* if no valid irq num given, find a free one */
for (i = irq_gsi_num(); i < NR_IRQS; i++) {
desc = &irq_desc_array[i];
if (desc->used == IRQ_NOT_ASSIGNED) {
irq = i;
break;
}
}
}
if (irq != IRQ_INVALID) {
desc = &irq_desc_array[irq];
desc->used = IRQ_ASSIGNED; desc->used = IRQ_ASSIGNED;
} }
spinlock_irqrestore_release(&desc->lock, rflags); spinlock_irqrestore_release(&irq_alloc_spinlock, rflags);
return irq; return irq;
} }
/* /*
* system find available irq and set assigned * free irq num allocated via alloc_irq_num()
* return: irq, VECTOR_INVALID not found
*/ */
static uint32_t alloc_irq(void) void free_irq_num(uint32_t irq)
{ {
uint32_t i;
uint64_t rflags;
struct irq_desc *desc; struct irq_desc *desc;
uint64_t rflags;
if (irq >= NR_IRQS) {
for (i = irq_gsi_num(); i < NR_IRQS; i++) { return;
desc = &irq_desc_array[i]; }
spinlock_irqsave_obtain(&desc->lock, &rflags);
if (desc->used == IRQ_NOT_ASSIGNED) { desc = &irq_desc_array[irq];
desc->used = IRQ_ASSIGNED; if ((irq_is_gsi(irq) == false)
spinlock_irqrestore_release(&desc->lock, rflags); && (desc->vector <= VECTOR_DYNAMIC_END)) {
break; spinlock_irqsave_obtain(&irq_alloc_spinlock, &rflags);
} desc->used = IRQ_NOT_ASSIGNED;
spinlock_irqrestore_release(&desc->lock, rflags); spinlock_irqrestore_release(&irq_alloc_spinlock, rflags);
} }
return (i == NR_IRQS) ? IRQ_INVALID : i;
} }
/* need lock protection before use */ /* need lock protection before use */
@ -163,12 +175,12 @@ static void disable_pic_irq(void)
pio_write8(0xffU, 0x21U); pio_write8(0xffU, 0x21U);
} }
int32_t request_irq(uint32_t irq_arg, int32_t request_irq(uint32_t req_irq,
irq_action_t action_fn, irq_action_t action_fn,
void *priv_data) void *priv_data)
{ {
struct irq_desc *desc; struct irq_desc *desc;
uint32_t irq = irq_arg, vector; uint32_t irq, vector;
uint64_t rflags; uint64_t rflags;
/* ====================================================== /* ======================================================
@ -198,18 +210,9 @@ int32_t request_irq(uint32_t irq_arg,
* *
* ===================================================== * =====================================================
*/ */
irq = alloc_irq_num(req_irq);
/* HV select a irq for device if irq < 0
* this vector/irq match to APCI DSDT or PCI INTx/MSI
*/
if (irq == IRQ_INVALID) { if (irq == IRQ_INVALID) {
irq = alloc_irq(); pr_err("[%s] invalid irq num", __func__);
} else {
irq = irq_mark_used(irq);
}
if (irq >= NR_IRQS) {
pr_err("failed to assign IRQ");
return -EINVAL; return -EINVAL;
} }
@ -228,7 +231,7 @@ int32_t request_irq(uint32_t irq_arg,
if (desc->vector == VECTOR_INVALID) { if (desc->vector == VECTOR_INVALID) {
pr_err("the input vector is not correct"); pr_err("the input vector is not correct");
/* FIXME: free allocated irq */ free_irq_num(irq);
return -EINVAL; return -EINVAL;
} }
@ -531,6 +534,7 @@ void free_irq(uint32_t irq)
spinlock_irqrestore_release(&desc->lock, rflags); spinlock_irqrestore_release(&desc->lock, rflags);
irq_desc_try_free_vector(desc->irq); irq_desc_try_free_vector(desc->irq);
free_irq_num(irq);
} }
#ifdef HV_DEBUG #ifdef HV_DEBUG

View File

@ -74,6 +74,8 @@ void setup_notification(void);
typedef void (*spurious_handler_t)(uint32_t vector); 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);
/* /*
* Some MSI message definitions * Some MSI message definitions
*/ */

View File

@ -34,8 +34,6 @@ struct irq_desc {
spinlock_t lock; spinlock_t lock;
}; };
uint32_t irq_mark_used(uint32_t irq);
uint32_t irq_desc_alloc_vector(uint32_t irq); uint32_t irq_desc_alloc_vector(uint32_t irq);
void irq_desc_try_free_vector(uint32_t irq); void irq_desc_try_free_vector(uint32_t irq);