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 */
#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
* 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);
#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;
-}
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 */
* 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
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 */
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
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
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