summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bl32/tsp/aarch64/tsp_exceptions.S2
-rw-r--r--bl32/tsp/tsp_interrupt.c45
-rw-r--r--bl32/tsp/tsp_private.h3
-rw-r--r--include/bl32/tsp/tsp.h1
-rw-r--r--services/spd/tspd/tspd_main.c47
5 files changed, 46 insertions, 52 deletions
diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S
index 4c0d4361..272d94b7 100644
--- a/bl32/tsp/aarch64/tsp_exceptions.S
+++ b/bl32/tsp/aarch64/tsp_exceptions.S
@@ -125,7 +125,7 @@ irq_sp_elx:
save_caller_regs_and_lr
/* We just update some statistics in the handler */
- bl tsp_irq_received
+ bl tsp_handle_preemption
/* Hand over control to the normal world to handle the IRQ */
smc #0
/* The resume std smc starts from here */
diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c
index 139642d0..d5379cdc 100644
--- a/bl32/tsp/tsp_interrupt.c
+++ b/bl32/tsp/tsp_interrupt.c
@@ -67,6 +67,25 @@ void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
#endif
}
+/******************************************************************************
+ * This function is invoked when a non S-EL1 interrupt is received and causes
+ * the preemption of TSP. This function returns TSP_PREEMPTED and results
+ * in the control being handed over to EL3 for handling the interrupt.
+ *****************************************************************************/
+int32_t tsp_handle_preemption(void)
+{
+ uint32_t linear_id = plat_my_core_pos();
+
+ tsp_stats[linear_id].preempt_intr_count++;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+ spin_lock(&console_lock);
+ VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n",
+ read_mpidr(), tsp_stats[linear_id].preempt_intr_count);
+ spin_unlock(&console_lock);
+#endif
+ return TSP_PREEMPTED;
+}
+
/*******************************************************************************
* TSP FIQ handler called as a part of both synchronous and asynchronous
* handling of FIQ interrupts. It returns 0 upon successfully handling a S-EL1
@@ -82,16 +101,21 @@ int32_t tsp_fiq_handler(void)
* Get the highest priority pending interrupt id and see if it is the
* secure physical generic timer interrupt in which case, handle it.
* Otherwise throw this interrupt at the EL3 firmware.
+ *
+ * There is a small time window between reading the highest priority
+ * pending interrupt and acknowledging it during which another
+ * interrupt of higher priority could become the highest pending
+ * interrupt. This is not expected to happen currently for TSP.
*/
id = plat_ic_get_pending_interrupt_id();
/* TSP can only handle the secure physical timer interrupt */
if (id != TSP_IRQ_SEC_PHY_TIMER)
- return TSP_EL3_FIQ;
+ return tsp_handle_preemption();
/*
- * Handle the interrupt. Also sanity check if it has been preempted by
- * another secure interrupt through an assertion.
+ * Acknowledge and handle the secure timer interrupt. Also sanity check
+ * if it has been preempted by another interrupt through an assertion.
*/
id = plat_ic_acknowledge_interrupt();
assert(id == TSP_IRQ_SEC_PHY_TIMER);
@@ -110,18 +134,3 @@ int32_t tsp_fiq_handler(void)
#endif
return 0;
}
-
-int32_t tsp_irq_received(void)
-{
- uint32_t linear_id = plat_my_core_pos();
-
- tsp_stats[linear_id].irq_count++;
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
- spin_lock(&console_lock);
- VERBOSE("TSP: cpu 0x%lx received irq\n", read_mpidr());
- VERBOSE("TSP: cpu 0x%lx: %d irq requests\n",
- read_mpidr(), tsp_stats[linear_id].irq_count);
- spin_unlock(&console_lock);
-#endif
- return TSP_PREEMPTED;
-}
diff --git a/bl32/tsp/tsp_private.h b/bl32/tsp/tsp_private.h
index 39fb5f66..346351c0 100644
--- a/bl32/tsp/tsp_private.h
+++ b/bl32/tsp/tsp_private.h
@@ -55,9 +55,10 @@
typedef struct work_statistics {
uint32_t fiq_count; /* Number of FIQs on this cpu */
- uint32_t irq_count; /* Number of IRQs on this cpu */
uint32_t sync_fiq_count; /* Number of sync. fiqs on this cpu */
uint32_t sync_fiq_ret_count; /* Number of fiq returns on this cpu */
+ /* Number of non s-el1 interrupts on this cpu which preempted TSP */
+ uint32_t preempt_intr_count;
uint32_t smc_count; /* Number of returns on this cpu */
uint32_t eret_count; /* Number of entries on this cpu */
uint32_t cpu_on_count; /* Number of cpu on requests */
diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h
index c6578b78..2286b3f1 100644
--- a/include/bl32/tsp/tsp.h
+++ b/include/bl32/tsp/tsp.h
@@ -50,7 +50,6 @@
* the TSPD after handling the interrupt else execution can remain in the TSP.
*/
#define TSP_HANDLED_S_EL1_FIQ 0xf2000006
-#define TSP_EL3_FIQ 0xf2000007
/* SMC function ID that TSP uses to request service from secure monitor */
#define TSP_GET_ARGS 0xf2001000
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
index 62231601..0d6e0d22 100644
--- a/services/spd/tspd/tspd_main.c
+++ b/services/spd/tspd/tspd_main.c
@@ -72,9 +72,16 @@ DEFINE_SVC_UUID(tsp_uuid,
int32_t tspd_init(void);
+/*
+ * This helper function handles Secure EL1 preemption. The preemption could be
+ * due Non Secure interrupts or EL3 interrupts. In both the cases we context
+ * switch to the normal world and in case of EL3 interrupts, it will again be
+ * routed to EL3 which will get handled at the exception vectors.
+ */
uint64_t tspd_handle_sp_preemption(void *handle)
{
cpu_context_t *ns_cpu_context;
+
assert(handle == cm_get_context(SECURE));
cm_el1_sysregs_context_save(SECURE);
/* Get a reference to the non-secure context */
@@ -88,8 +95,16 @@ uint64_t tspd_handle_sp_preemption(void *handle)
cm_el1_sysregs_context_restore(NON_SECURE);
cm_set_next_eret_context(NON_SECURE);
+ /*
+ * We need to restore non secure context according to
+ * the SEL1 context which got preempted and currently
+ * TSP can only be preempted when a STD SMC is ongoing.
+ * Return SMC_PREEMPTED in x0 and restore non secure
+ * context.
+ */
SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
}
+
/*******************************************************************************
* This function is the handler registered for S-EL1 interrupts by the TSPD. It
* validates the interrupt and upon success arranges entry into the TSP at
@@ -356,35 +371,6 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
SMC_RET0((uint64_t) ns_cpu_context);
-
- /*
- * This function ID is used only by the TSP to indicate that it was
- * interrupted due to a EL3 FIQ interrupt. Execution should resume
- * in the normal world.
- */
- case TSP_EL3_FIQ:
- if (ns)
- SMC_RET1(handle, SMC_UNK);
-
- assert(handle == cm_get_context(SECURE));
-
- /* Assert that standard SMC execution has been preempted */
- assert(get_std_smc_active_flag(tsp_ctx->state));
-
- /* Save the secure system register state */
- cm_el1_sysregs_context_save(SECURE);
-
- /* Get a reference to the non-secure context */
- ns_cpu_context = cm_get_context(NON_SECURE);
- assert(ns_cpu_context);
-
- /* Restore non-secure state */
- cm_el1_sysregs_context_restore(NON_SECURE);
- cm_set_next_eret_context(NON_SECURE);
-
- SMC_RET1(ns_cpu_context, TSP_EL3_FIQ);
-
-
/*
* This function ID is used only by the SP to indicate it has
* finished initialising itself after a cold boot
@@ -438,8 +424,7 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
panic();
/*
- * Disable the interrupt NS locally since it will be enabled globally
- * within cm_init_my_context.
+ * Disable the NS interrupt locally.
*/
disable_intr_rm_local(INTR_TYPE_NS, SECURE);
#endif