summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDietmar Eggemann <dietmar.eggemann@arm.com>2012-03-15 14:59:41 +0000
committerDietmar Eggemann <dietmar.eggemann@arm.com>2012-05-22 10:43:46 +0100
commit4112d8f52fcdc6b76bf82a44be48a66fce1fbada (patch)
tree3a0254579818160b825040f2c5bf188ecd879dc1
parent0b0dfb1c222362944bce728357551a88c99997d6 (diff)
Virqmig: Complete interoperability with hotplug.
Signed-off-by: Achin Gupta <achin.gupta@arm.com> Signed-off-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
-rwxr-xr-xbig-little/common/pagetable_setup.c8
-rw-r--r--big-little/common/vgic_handle.c4
-rw-r--r--big-little/common/vgiclib.c18
-rw-r--r--big-little/virtualisor/vgic_trap_handler.c11
-rw-r--r--big-little/virtualisor/virt_setup.c18
5 files changed, 33 insertions, 26 deletions
diff --git a/big-little/common/pagetable_setup.c b/big-little/common/pagetable_setup.c
index 4a25a8f..431e047 100755
--- a/big-little/common/pagetable_setup.c
+++ b/big-little/common/pagetable_setup.c
@@ -379,6 +379,14 @@ void Create2ndStagePageTables(void)
l3_desc.pt_addr = stage2_l3_cpuif_pt;
Add4KMapping(&l3_desc);
+ /* 4KB Mapping for trapping GIC Distributor accesses */
+ l3_desc.va = GIC_ID_PHY_BASE;
+ l3_desc.pa = GIC_ID_PHY_BASE;
+ l3_desc.attrs = ACCESS_FLAG | SHAREABILITY(0x3) | ACCESS_PERM(0x3) |
+ MEM_ATTR(0x1);
+ l3_desc.pt_addr = stage2_l3_cpuif_pt;
+ Add4KMapping(&l3_desc);
+
/*
* Create a mapping for a device page to be used
* for Locks, Events & anything that is shared when both
diff --git a/big-little/common/vgic_handle.c b/big-little/common/vgic_handle.c
index 0e20dcf..960f97d 100644
--- a/big-little/common/vgic_handle.c
+++ b/big-little/common/vgic_handle.c
@@ -160,7 +160,9 @@ vm_context *handle_interrupt(vm_context * context)
break;
case IPI_MIGRATE_VIRQS:
- complete_virq_migration(src_cpu);
+ /* Refer to comments in vgic_trap_handler.c */
+ if (FALSE == async_switchover)
+ complete_virq_migration(src_cpu);
return ret_ctx;
default:
diff --git a/big-little/common/vgiclib.c b/big-little/common/vgiclib.c
index 5f5735b..ffe1be9 100644
--- a/big-little/common/vgiclib.c
+++ b/big-little/common/vgiclib.c
@@ -25,11 +25,13 @@
#include "virt_helpers.h"
#include "int_master.h"
#include "ipi.h"
+#include "events.h"
+
+extern unsigned get_cpuinfo(unsigned);
/*
* Manage overflowints somehow.. static pool with recycling allocators.
*/
-
#define MAXOVERFLOWINTS 200
static struct overflowint *freeoverflows[NUM_CPUS];
@@ -170,6 +172,7 @@ unsigned start_virq_migration(unsigned orig, unsigned curr, unsigned icdiptr_off
*/
if (virq_mig_mask) {
send_hyp_ipi(virq_mig_mask, IPI_MIGRATE_VIRQS);
+ wait_for_events(VIRQ_MIG_DONE, get_cpu_mask(virq_mig_mask));
return 1;
}
@@ -183,16 +186,19 @@ void complete_virq_migration(unsigned src_cpuid)
{
unsigned ctr, cpu_id = read_cpuid();
unsigned cluster_id = read_clusterid();
- unsigned dest_cpuif = get_cpuif(cluster_id, cpu_id);
+ unsigned dest_cpuid = 0;
for (ctr = 0; ctr < MAX_MIG_IRQS; ctr++) {
- if (migrated_irqs[src_cpuid][ctr].desc &&
- migrated_irqs[src_cpuid][ctr].dest_cpuif == dest_cpuif) {
+ /*
+ * Compare the cpu id instead of the cpu interface id in case
+ * a switch took place before the virq migration ipi was recieved.
+ */
+ dest_cpuid = get_cpuinfo(migrated_irqs[src_cpuid][ctr].dest_cpuif) & 0xf;
+ if (migrated_irqs[src_cpuid][ctr].desc && dest_cpuid == cpu_id)
enqueue_interrupt(migrated_irqs[src_cpuid][ctr].desc, cpu_id);
- }
}
-// set_event(VIRQ_MIG_DONE, src_cpuid);
+ set_event(VIRQ_MIG_DONE, src_cpuid);
return;
}
diff --git a/big-little/virtualisor/vgic_trap_handler.c b/big-little/virtualisor/vgic_trap_handler.c
index 5e64eea..cd06578 100644
--- a/big-little/virtualisor/vgic_trap_handler.c
+++ b/big-little/virtualisor/vgic_trap_handler.c
@@ -25,6 +25,7 @@
#include "misc.h"
#include "virt_helpers.h"
#include "vgiclib.h"
+#include "int_master.h"
/*
* Whether A15 or A7, the distributor accesses are virtualised in
@@ -51,7 +52,15 @@ void handle_vgic_distif_abort(unsigned pa, unsigned *data, unsigned write)
write32(pa, value);
icdiptr_curr = value;
- start_virq_migration(icdiptr_orig, icdiptr_curr, reg_offset - GICD_CPUS);
+ /*
+ * Virtual irq migration needs communication with another cpu in
+ * HYP mode. A cluster switch while doing this can cause a deadlock
+ * and there is no easy way around this. So the assumption is that
+ * the OS will prevent a switch while an irq migration operation is
+ * in progress.
+ */
+ if (FALSE == async_switchover)
+ start_virq_migration(icdiptr_orig, icdiptr_curr, reg_offset - GICD_CPUS);
} else {
value = read32(pa);
diff --git a/big-little/virtualisor/virt_setup.c b/big-little/virtualisor/virt_setup.c
index d35adc6..4403ae2 100644
--- a/big-little/virtualisor/virt_setup.c
+++ b/big-little/virtualisor/virt_setup.c
@@ -130,24 +130,6 @@ void SetupVirtualisor(unsigned first_cpu)
}
- /*
- * Irrespective of what cpu types are present in the
- * dual cluster system, the host cluster has to trap
- * accesses to the vgic distributor when switching.
- */
- if (switcher && cluster_id == host_cluster) {
- if (cpu_id == first_cpu) {
- rc = mem_trap_setup(GIC_ID_PHY_BASE,
- &svgic_distif_trap);
- if (rc) {
- printf
- ("%s: svgic distif trap setup failed \n",
- __FUNCTION__);
- goto out;
- }
- }
- }
-
/*
* If the two clusters have different cpu types, then the
* target saves its midr and the host uses the value to