summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDietmar Eggemann <dietmar.eggemann@arm.com>2012-03-15 15:06:45 +0000
committerDietmar Eggemann <dietmar.eggemann@arm.com>2012-05-22 10:43:46 +0100
commit66a66968cbebd8d140d2f8843419829c01b81731 (patch)
tree42b915dbe519641b0a3de64a875e813cdbce1371
parent4112d8f52fcdc6b76bf82a44be48a66fce1fbada (diff)
downloadswitcher-66a66968cbebd8d140d2f8843419829c01b81731.tar.gz
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.c41
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 */