summaryrefslogtreecommitdiff
path: root/big-little/common/vgic_handle.c
diff options
context:
space:
mode:
Diffstat (limited to 'big-little/common/vgic_handle.c')
-rw-r--r--big-little/common/vgic_handle.c263
1 files changed, 132 insertions, 131 deletions
diff --git a/big-little/common/vgic_handle.c b/big-little/common/vgic_handle.c
index 0280c38..b6bc29c 100644
--- a/big-little/common/vgic_handle.c
+++ b/big-little/common/vgic_handle.c
@@ -18,7 +18,7 @@
* contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
- */
+ */
#include "int_master.h"
#include "gic_registers.h"
@@ -42,49 +42,49 @@ unsigned async_switchover = ASYNC_SWITCH;
void gic_send_ipi(unsigned cpu_mask, unsigned ipi_num)
{
- write32(GIC_ID_PHY_BASE + GICD_SW,
- ((cpu_mask & 0xff) << 16) | (ipi_num & 0xf));
+ write32(GIC_ID_PHY_BASE + GICD_SW,
+ ((cpu_mask & 0xff) << 16) | (ipi_num & 0xf));
}
void gic_enable_int(unsigned num)
{
- unsigned int regbase;
+ unsigned int regbase;
- regbase = GIC_ID_PHY_BASE + GICD_ENABLESET + ((num >> 5) << 2);
- write32(regbase, 1 << (num & 0x1F));
+ regbase = GIC_ID_PHY_BASE + GICD_ENABLESET + ((num >> 5) << 2);
+ write32(regbase, 1 << (num & 0x1F));
}
void gic_disable_int(unsigned num)
{
- unsigned int regbase;
+ unsigned int regbase;
- regbase = GIC_ID_PHY_BASE + GICD_ENABLECLEAR + ((num >> 5) << 2);
- write32(regbase, 1 << (num & 0x1F));
+ regbase = GIC_ID_PHY_BASE + GICD_ENABLECLEAR + ((num >> 5) << 2);
+ write32(regbase, 1 << (num & 0x1F));
}
void gic_deactivate_int(unsigned num)
{
- write32(GIC_IC_PHY_BASE + GICC_DEACTIVATE, num);
+ write32(GIC_IC_PHY_BASE + GICC_DEACTIVATE, num);
}
void gic_eoi_int(unsigned num)
{
- write32(GIC_IC_PHY_BASE + GICC_EOI, num);
+ write32(GIC_IC_PHY_BASE + GICC_EOI, num);
}
unsigned gic_ack_int(void)
{
- return read32(GIC_IC_PHY_BASE + GICC_INTACK);
+ return read32(GIC_IC_PHY_BASE + GICC_INTACK);
}
unsigned gic_int_num(void)
{
- unsigned intcount = 0;
+ unsigned intcount = 0;
- intcount = read32(GIC_ID_PHY_BASE + GICD_CTR);
- intcount = ((intcount & 0x1F) + 1) * 32;
+ intcount = read32(GIC_ID_PHY_BASE + GICD_CTR);
+ intcount = ((intcount & 0x1F) + 1) * 32;
- return intcount;
+ return intcount;
}
/*
@@ -92,119 +92,120 @@ unsigned gic_int_num(void)
*/
vm_context *handle_interrupt(vm_context * context)
{
- unsigned int status, i, src_cpu = 0;
- unsigned cpuid = read_cpuid();
- unsigned cluster_id = read_clusterid();
- unsigned list_desc = 0;
- unsigned int_pri = 0;
- unsigned cpu_if = get_cpuif(cluster_id, cpuid);
- vm_context *ret_ctx = context;
- unsigned do_switch = 0, first_cpu = find_first_cpu();
-
- /*
- * Get the interrupt #
- */
- status = gic_ack_int();
- i = status & 0x3FF;
-
- /*
- * Stop if there are no more interrupts
- */
- if (i == 1023) {
- printf("Spurious interrupt %d \n", i);
- return ret_ctx;
- }
-
- if (async_switchover && cpuid == first_cpu)
- keep_trigger_alive();
-
- /*
- * Special case IPIs, since we need the source CPU ID
- */
- if (i < 16) {
- src_cpu = (status >> 10) & INTACK_CPUID_MASK;
-
- /* Check whether we have been requested to switchover */
- do_switch = check_switchover_ipi(cpu_if, i);
-
- /*
- * SGI Ack actually returns the source cpu interface
- * which needs to be mapped to the apt cpuid.
- */
- src_cpu = get_cpuinfo(src_cpu) & 0xf;
-
- /*
- * IPI handling:
- * If Split EOI is not enabled, then writing to the EOI
- * register drops the priority and deactivates the IPI
- * together. Otherwise, we need to do it seperately.
- * Note that in either case, the OS cannot deactivate the
- * IPI as writing to the virtual EOI register will not
- * bring about a state change in the physical distributor
- * state machine.
- */
- gic_eoi_int(status);
- if (read32(GIC_IC_PHY_BASE + GICC_CTL) & 0x200)
- gic_deactivate_int(status);
-
- if (do_switch) {
- /*
- * switch_cluster() takes the first_cpu as its arg. Since
- * all the cores are expected to power down, its reasonable
- * to assume cpu0 is the first cpu and will take care of
- * saving all the global context.
- */
- switch_cluster(first_cpu);
- return ret_ctx;
- }
- }
-
- /*
- * Check if this interrupt is meant to trigger to switch to the
- * other cluster. If so, then we do not forward the interrupt
- * to the payload software.
- */
- if (async_switchover && check_trigger(i, status))
- return ret_ctx;
-
- /*
- * TODO: Further optimizations can be done later when there are
- * more interrupts apart from timer & uart.
- */
- /*
- * vGIC 11.0 onwards split EOI functionality has to be used for
- * all interrupts. EOIing the interrupt from the VCPUIF will only
- * deactivate the interrupt (clear the active bit) and not clear
- * the active priority at the PCPUIF.
- * Do this only for non SGIs as their priority has already been
- * dropped.
- */
- if (i >= 16)
- write32(GIC_IC_PHY_BASE + GICC_PRIODROP, i);
-
- /*
- * Priority reg = (interrupt no. / 4) x 4 bytes.
- * Priority index = interrupt no. % 4 x 8 bits (8 bits for each priority value)
- * Prioriity value = Priority reg >> Priority index
- */
- int_pri =
- read32(GIC_ID_PHY_BASE + GICD_PRI +
- ((i >> 2) << 2)) >> ((i & 0x3) << 3);
-
- /*
- * Signal interrupts as secure to the VCPUIF since the OS will write to the EnableS
- * bit of the VCPUIF through the 2nd stage translations.
- * TODO: Priority is being read as a 8 bit value from the distributor registers
- * and passed as a 5 bit value. Need to check if this will cause problems.
- */
- if (i < 16)
- list_desc =
- STATE(PENDING) | (int_pri >> 3) << 23 | src_cpu << 10 | i;
- else
- list_desc =
- HW_IRQ | STATE(PENDING) | (int_pri >> 3) << 23 | i << 10 | i;
-
- enqueue_interrupt(list_desc, cpuid);
-
- return ret_ctx;
+ unsigned int status, i, src_cpu = 0;
+ unsigned cpuid = read_cpuid();
+ unsigned cluster_id = read_clusterid();
+ unsigned list_desc = 0;
+ unsigned int_pri = 0;
+ unsigned cpu_if = get_cpuif(cluster_id, cpuid);
+ vm_context *ret_ctx = context;
+ unsigned do_switch = 0, first_cpu = find_first_cpu();
+
+ /*
+ * Get the interrupt #
+ */
+ status = gic_ack_int();
+ i = status & 0x3FF;
+
+ /*
+ * Stop if there are no more interrupts
+ */
+ if (i == 1023) {
+ printf("Spurious interrupt %d \n", i);
+ return ret_ctx;
+ }
+
+ if (async_switchover && cpuid == first_cpu)
+ keep_trigger_alive();
+
+ /*
+ * Special case IPIs, since we need the source CPU ID
+ */
+ if (i < 16) {
+ src_cpu = (status >> 10) & INTACK_CPUID_MASK;
+
+ /* Check whether we have been requested to switchover */
+ do_switch = check_switchover_ipi(cpu_if, i);
+
+ /*
+ * SGI Ack actually returns the source cpu interface
+ * which needs to be mapped to the apt cpuid.
+ */
+ src_cpu = get_cpuinfo(src_cpu) & 0xf;
+
+ /*
+ * IPI handling:
+ * If Split EOI is not enabled, then writing to the EOI
+ * register drops the priority and deactivates the IPI
+ * together. Otherwise, we need to do it seperately.
+ * Note that in either case, the OS cannot deactivate the
+ * IPI as writing to the virtual EOI register will not
+ * bring about a state change in the physical distributor
+ * state machine.
+ */
+ gic_eoi_int(status);
+ if (read32(GIC_IC_PHY_BASE + GICC_CTL) & 0x200)
+ gic_deactivate_int(status);
+
+ if (do_switch) {
+ /*
+ * switch_cluster() takes the first_cpu as its arg. Since
+ * all the cores are expected to power down, its reasonable
+ * to assume cpu0 is the first cpu and will take care of
+ * saving all the global context.
+ */
+ switch_cluster(first_cpu);
+ return ret_ctx;
+ }
+ }
+
+ /*
+ * Check if this interrupt is meant to trigger to switch to the
+ * other cluster. If so, then we do not forward the interrupt
+ * to the payload software.
+ */
+ if (async_switchover && check_trigger(i, status))
+ return ret_ctx;
+
+ /*
+ * TODO: Further optimizations can be done later when there are
+ * more interrupts apart from timer & uart.
+ */
+ /*
+ * vGIC 11.0 onwards split EOI functionality has to be used for
+ * all interrupts. EOIing the interrupt from the VCPUIF will only
+ * deactivate the interrupt (clear the active bit) and not clear
+ * the active priority at the PCPUIF.
+ * Do this only for non SGIs as their priority has already been
+ * dropped.
+ */
+ if (i >= 16)
+ write32(GIC_IC_PHY_BASE + GICC_PRIODROP, i);
+
+ /*
+ * Priority reg = (interrupt no. / 4) x 4 bytes.
+ * Priority index = interrupt no. % 4 x 8 bits (8 bits for each priority value)
+ * Prioriity value = Priority reg >> Priority index
+ */
+ int_pri =
+ read32(GIC_ID_PHY_BASE + GICD_PRI +
+ ((i >> 2) << 2)) >> ((i & 0x3) << 3);
+
+ /*
+ * Signal interrupts as secure to the VCPUIF since the OS will write to the EnableS
+ * bit of the VCPUIF through the 2nd stage translations.
+ * TODO: Priority is being read as a 8 bit value from the distributor registers
+ * and passed as a 5 bit value. Need to check if this will cause problems.
+ */
+ if (i < 16)
+ list_desc =
+ STATE(PENDING) | (int_pri >> 3) << 23 | src_cpu << 10 | i;
+ else
+ list_desc =
+ HW_IRQ | STATE(PENDING) | (int_pri >> 3) << 23 | i << 10 |
+ i;
+
+ enqueue_interrupt(list_desc, cpuid);
+
+ return ret_ctx;
}