diff options
-rw-r--r-- | big-little/common/vgiclib.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/big-little/common/vgiclib.c b/big-little/common/vgiclib.c index ffe1be9..a55fcc4 100644 --- a/big-little/common/vgiclib.c +++ b/big-little/common/vgiclib.c @@ -41,6 +41,12 @@ static unsigned hv_lr_count[NUM_CPUS] = { 0 }; static mig_irq_info migrated_irqs[NUM_CPUS][MAX_MIG_IRQS] = {0}; +static void free_overflowint(struct overflowint *p, unsigned cpuid) +{ + p->next = freeoverflows[cpuid]; + freeoverflows[cpuid] = p; +} + /* * The vGIC spec implements 64 list registers across two 32-bit status * registers. Since all of the list registers may not be implemented, @@ -89,14 +95,17 @@ static unsigned get_elrsr_active_bits(unsigned index, unsigned cpuid, */ static unsigned dequeue_virq(unsigned irq, unsigned cpu_id) { - unsigned virq_desc = 0, max_index = elrsr_max_index(cpu_id), ctr = 0; + unsigned list_reg = 0, max_index = elrsr_max_index(cpu_id), ctr = 0; unsigned cur_elrsr = 0, i = 0; + struct gic_cpuif *cpuif = &cpuifs[cpu_id]; + struct overflowint *ovflow = cpuif->overflow, *ovflowp = cpuif->overflow; + /* First check the hw list registers */ for (ctr = 0; ctr <= max_index; ctr++) { cur_elrsr = get_elrsr_active_bits(ctr, cpu_id, max_index); for (i = bitindex(cur_elrsr); ((int)i) >= 0; i = bitindex(cur_elrsr)) { - unsigned list_reg = 0, int_id = 0; + unsigned int_id = 0; list_reg = read32(VGIC_HV_PHY_BASE + GICH_LR_BASE + ((1 << 7) * ctr) + (i << 2)); int_id = (list_reg >> 10) & 0x3ff; @@ -104,17 +113,36 @@ static unsigned dequeue_virq(unsigned irq, unsigned cpu_id) /* Clear the current bit */ cur_elrsr &= ~(1 << i); + /* Set this entry as free */ + cpuif->freelist |= (1 << i); + if (irq == int_id) { /* * Invalidate the list register entry if the ids match and return */ write32(VGIC_HV_PHY_BASE + GICH_LR_BASE + ((1 << 7) * ctr) + (i << 2), list_reg & ~(0x3 << 28)); - return virq_desc; + return list_reg; } } } + /* Check the sw linked list for the presence of this interrupt */ + while (ovflow) { + unsigned int_id = (ovflow->value >> 10 )& 0x3ff; + unsigned type = ovflow->value & HW_IRQ; + + if ((type == HW_IRQ) && (int_id == irq)) { + list_reg = cpuif->overflow->value; + ovflowp = ovflow; + ovflow = ovflow->next; + free_overflowint(ovflowp, cpu_id); + break; + } + + ovflow = ovflow->next; + } + return 0; } @@ -231,12 +259,6 @@ static struct overflowint *get_overflowint(unsigned cpuid) return p; } -static void free_overflowint(struct overflowint *p, unsigned cpuid) -{ - p->next = freeoverflows[cpuid]; - freeoverflows[cpuid] = p; -} - void vgic_init(void) { unsigned int i; @@ -379,6 +401,7 @@ void vgic_savestate(unsigned int cpu) cpuif->status = read32(VGIC_HV_PHY_BASE + GICH_CTL); cpuif->activepris = read32(VGIC_HV_PHY_BASE + GICH_APR0); + cpuif->freelist = read32(VGIC_HV_PHY_BASE + GICH_APR0); write32(VGIC_HV_PHY_BASE + GICH_CTL, 0); /* SMP */ |