diff options
author | Dietmar Eggemann <dietmar.eggemann@arm.com> | 2012-03-15 15:06:45 +0000 |
---|---|---|
committer | Dietmar Eggemann <dietmar.eggemann@arm.com> | 2012-05-22 10:43:46 +0100 |
commit | 66a66968cbebd8d140d2f8843419829c01b81731 (patch) | |
tree | 42b915dbe519641b0a3de64a875e813cdbce1371 | |
parent | 4112d8f52fcdc6b76bf82a44be48a66fce1fbada (diff) |
Virqmig: Added support for migrating sw maintained virqs
Prior to this patch, while migrating virtual interrupts only the hw list
registers were being checked for a !inactive virtual interrupt. It could be
present in the sw maintained list of virqs in case of an overflow of the list
registers. Hence, the added check.
Signed-off-by: Achin Gupta <achin.gupta@arm.com>
Signed-off-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
-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 */ |