1 /* 2 * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <assert.h> 33 #include <debug.h> 34 #include <platform.h> 35 #include <platform_def.h> 36 #include <tsp.h> 37 #include "tsp_private.h" 38 39 /******************************************************************************* 40 * This function updates the TSP statistics for S-EL1 interrupts handled 41 * synchronously i.e the ones that have been handed over by the TSPD. It also 42 * keeps count of the number of times control was passed back to the TSPD 43 * after handling the interrupt. In the future it will be possible that the 44 * TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to 45 * return execution. This statistic will be useful to distinguish between these 46 * two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter 47 * contains the address of the instruction in normal world where this S-EL1 48 * interrupt was generated. 49 ******************************************************************************/ 50 void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3) 51 { 52 uint32_t linear_id = plat_my_core_pos(); 53 54 tsp_stats[linear_id].sync_sel1_intr_count++; 55 if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN) 56 tsp_stats[linear_id].sync_sel1_intr_ret_count++; 57 58 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 59 spin_lock(&console_lock); 60 VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%lx\n", 61 read_mpidr(), elr_el3); 62 VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests," 63 " %d sync s-el1 interrupt returns\n", 64 read_mpidr(), 65 tsp_stats[linear_id].sync_sel1_intr_count, 66 tsp_stats[linear_id].sync_sel1_intr_ret_count); 67 spin_unlock(&console_lock); 68 #endif 69 } 70 71 /****************************************************************************** 72 * This function is invoked when a non S-EL1 interrupt is received and causes 73 * the preemption of TSP. This function returns TSP_PREEMPTED and results 74 * in the control being handed over to EL3 for handling the interrupt. 75 *****************************************************************************/ 76 int32_t tsp_handle_preemption(void) 77 { 78 uint32_t linear_id = plat_my_core_pos(); 79 80 tsp_stats[linear_id].preempt_intr_count++; 81 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 82 spin_lock(&console_lock); 83 VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n", 84 read_mpidr(), tsp_stats[linear_id].preempt_intr_count); 85 spin_unlock(&console_lock); 86 #endif 87 return TSP_PREEMPTED; 88 } 89 90 /******************************************************************************* 91 * TSP interrupt handler is called as a part of both synchronous and 92 * asynchronous handling of TSP interrupts. Currently the physical timer 93 * interrupt is the only S-EL1 interrupt that this handler expects. It returns 94 * 0 upon successfully handling the expected interrupt and all other 95 * interrupts are treated as normal world or EL3 interrupts. 96 ******************************************************************************/ 97 int32_t tsp_common_int_handler(void) 98 { 99 uint32_t linear_id = plat_my_core_pos(), id; 100 101 /* 102 * Get the highest priority pending interrupt id and see if it is the 103 * secure physical generic timer interrupt in which case, handle it. 104 * Otherwise throw this interrupt at the EL3 firmware. 105 * 106 * There is a small time window between reading the highest priority 107 * pending interrupt and acknowledging it during which another 108 * interrupt of higher priority could become the highest pending 109 * interrupt. This is not expected to happen currently for TSP. 110 */ 111 id = plat_ic_get_pending_interrupt_id(); 112 113 /* TSP can only handle the secure physical timer interrupt */ 114 if (id != TSP_IRQ_SEC_PHY_TIMER) 115 return tsp_handle_preemption(); 116 117 /* 118 * Acknowledge and handle the secure timer interrupt. Also sanity check 119 * if it has been preempted by another interrupt through an assertion. 120 */ 121 id = plat_ic_acknowledge_interrupt(); 122 assert(id == TSP_IRQ_SEC_PHY_TIMER); 123 tsp_generic_timer_handler(); 124 plat_ic_end_of_interrupt(id); 125 126 /* Update the statistics and print some messages */ 127 tsp_stats[linear_id].sel1_intr_count++; 128 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE 129 spin_lock(&console_lock); 130 VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n", 131 read_mpidr(), id); 132 VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n", 133 read_mpidr(), tsp_stats[linear_id].sel1_intr_count); 134 spin_unlock(&console_lock); 135 #endif 136 return 0; 137 } 138