diff options
Diffstat (limited to 'security/tf_driver/tf_comm_tz.c')
-rw-r--r-- | security/tf_driver/tf_comm_tz.c | 911 |
1 files changed, 0 insertions, 911 deletions
diff --git a/security/tf_driver/tf_comm_tz.c b/security/tf_driver/tf_comm_tz.c deleted file mode 100644 index 0f36209add7a..000000000000 --- a/security/tf_driver/tf_comm_tz.c +++ /dev/null @@ -1,911 +0,0 @@ -/** - * Copyright (c) 2011 Trusted Logic S.A. - * All Rights Reserved. - * - * Copyright (C) 2011-2012 NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <asm/div64.h> -#include <asm/system.h> -#include <linux/version.h> -#include <asm/cputype.h> -#include <linux/interrupt.h> -#include <linux/page-flags.h> -#include <linux/pagemap.h> -#include <linux/vmalloc.h> -#include <linux/jiffies.h> - -#include <trace/events/nvsecurity.h> - -#include "tf_defs.h" -#include "tf_comm.h" -#include "tf_protocol.h" -#include "tf_util.h" -#include "tf_conn.h" - -/* - * Structure common to all SMC operations - */ -struct tf_generic_smc { - u32 reg0; - u32 reg1; - u32 reg2; - u32 reg3; - u32 reg4; -}; - -/*---------------------------------------------------------------------------- - * SMC operations - *----------------------------------------------------------------------------*/ - -static inline void tf_smc_generic_call( - struct tf_generic_smc *generic_smc) -{ -#ifdef CONFIG_SMP - long ret; - cpumask_t saved_cpu_mask; - cpumask_t local_cpu_mask = CPU_MASK_NONE; - - cpu_set(0, local_cpu_mask); - cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current)); - ret = sched_setaffinity(0, &local_cpu_mask); - if (ret != 0) - dprintk(KERN_ERR "sched_setaffinity #1 -> 0x%lX", ret); -#endif - - trace_smc_generic_call(NVSEC_SMC_START); - - __asm__ volatile( - "mov r0, %2\n" - "mov r1, %3\n" - "mov r2, %4\n" - "mov r3, %5\n" - "mov r4, %6\n" - ".word 0xe1600070 @ SMC 0\n" - "mov %0, r0\n" - "mov %1, r1\n" - : "=r" (generic_smc->reg0), "=r" (generic_smc->reg1) - : "r" (generic_smc->reg0), "r" (generic_smc->reg1), - "r" (generic_smc->reg2), "r" (generic_smc->reg3), - "r" (generic_smc->reg4) - : "r0", "r1", "r2", "r3", "r4"); - - trace_smc_generic_call(NVSEC_SMC_DONE); - -#ifdef CONFIG_SMP - ret = sched_setaffinity(0, &saved_cpu_mask); - if (ret != 0) - dprintk(KERN_ERR "sched_setaffinity #2 -> 0x%lX", ret); -#endif -} - -/* - * Calls the get protocol version SMC. - * Fills the parameter pProtocolVersion with the version number returned by the - * SMC - */ -static inline void tf_smc_get_protocol_version(u32 *protocol_version) -{ - struct tf_generic_smc generic_smc; - - generic_smc.reg0 = TF_SMC_GET_PROTOCOL_VERSION; - generic_smc.reg1 = 0; - generic_smc.reg2 = 0; - generic_smc.reg3 = 0; - generic_smc.reg4 = 0; - - tf_smc_generic_call(&generic_smc); - *protocol_version = generic_smc.reg1; -} - - -/* - * Calls the init SMC with the specified parameters. - * Returns zero upon successful completion, or an appropriate error code upon - * failure. - */ -static inline int tf_smc_init(u32 shared_page_descriptor) -{ - struct tf_generic_smc generic_smc; - - generic_smc.reg0 = TF_SMC_INIT; - /* Descriptor for the layer 1 shared buffer */ - generic_smc.reg1 = shared_page_descriptor; - generic_smc.reg2 = 0; - generic_smc.reg3 = 0; - generic_smc.reg4 = 0; - - tf_smc_generic_call(&generic_smc); - if (generic_smc.reg0 != S_SUCCESS) - printk(KERN_ERR "tf_smc_init:" - " r0=0x%08X upon return (expected 0x%08X)!\n", - generic_smc.reg0, - S_SUCCESS); - - return generic_smc.reg0; -} - - -/* - * Calls the reset irq SMC. - */ -static inline void tf_smc_reset_irq(void) -{ - struct tf_generic_smc generic_smc; - - generic_smc.reg0 = TF_SMC_RESET_IRQ; - generic_smc.reg1 = 0; - generic_smc.reg2 = 0; - generic_smc.reg3 = 0; - generic_smc.reg4 = 0; - - tf_smc_generic_call(&generic_smc); -} - - -/* - * Calls the WAKE_UP SMC. - * Returns zero upon successful completion, or an appropriate error code upon - * failure. - */ -static inline int tf_smc_wake_up(u32 l1_shared_buffer_descriptor, - u32 shared_mem_start_offset, - u32 shared_mem_size) -{ - struct tf_generic_smc generic_smc; - - generic_smc.reg0 = TF_SMC_WAKE_UP; - generic_smc.reg1 = shared_mem_start_offset; - /* long form command */ - generic_smc.reg2 = shared_mem_size | 0x80000000; - generic_smc.reg3 = l1_shared_buffer_descriptor; - generic_smc.reg4 = 0; - - tf_smc_generic_call(&generic_smc); - - if (generic_smc.reg0 != S_SUCCESS) - printk(KERN_ERR "tf_smc_wake_up:" - " r0=0x%08X upon return (expected 0x%08X)!\n", - generic_smc.reg0, - S_SUCCESS); - - return generic_smc.reg0; -} - -/* - * Calls the N-Yield SMC. - */ -static inline void tf_smc_nyield(void) -{ - struct tf_generic_smc generic_smc; - - generic_smc.reg0 = TF_SMC_N_YIELD; - generic_smc.reg1 = 0; - generic_smc.reg2 = 0; - generic_smc.reg3 = 0; - generic_smc.reg4 = 0; - - tf_smc_generic_call(&generic_smc); -} - -#ifdef CONFIG_SECURE_TRACES -static void tf_print_secure_traces(struct tf_comm *comm) -{ - spin_lock(&(comm->lock)); - if (comm->l1_buffer->traces_status != 0) { - if (comm->l1_buffer->traces_status > 1) - pr_info("TF : traces lost...\n"); - pr_info("TF : %s", comm->l1_buffer->traces_buffer); - comm->l1_buffer->traces_status = 0; - } - spin_unlock(&(comm->lock)); -} -#endif - -/* Yields the Secure World */ -int tf_schedule_secure_world(struct tf_comm *comm) -{ - tf_set_current_time(comm); - - /* yield to the Secure World */ - tf_smc_nyield(); - -#ifdef CONFIG_SECURE_TRACES - tf_print_secure_traces(comm); -#endif - - return 0; -} - -/* - * Returns the L2 descriptor for the specified user page. - */ - -#define L2_INIT_DESCRIPTOR_BASE (0x00000003) -#define L2_INIT_DESCRIPTOR_V13_12_SHIFT (4) - -static u32 tf_get_l2init_descriptor(u32 vaddr) -{ - struct page *page; - u32 paddr; - u32 descriptor; - - descriptor = L2_INIT_DESCRIPTOR_BASE; - - /* get physical address and add to descriptor */ - page = virt_to_page(vaddr); - paddr = page_to_phys(page); - descriptor |= (paddr & L2_DESCRIPTOR_ADDR_MASK); - - /* Add virtual address v[13:12] bits to descriptor */ - descriptor |= (DESCRIPTOR_V13_12_GET(vaddr) - << L2_INIT_DESCRIPTOR_V13_12_SHIFT); - - descriptor |= tf_get_l2_descriptor_common(vaddr, &init_mm); - - - return descriptor; -} - - -/*---------------------------------------------------------------------------- - * Power management - *----------------------------------------------------------------------------*/ - -/* - * Free the memory used by the W3B buffer for the specified comm. - * This function does nothing if no W3B buffer is allocated for the device. - */ -static inline void tf_free_w3b(struct tf_comm *comm) -{ - tf_cleanup_shared_memory( - &(comm->w3b_cpt_alloc_context), - &(comm->w3b_shmem_desc), - 0); - - tf_release_coarse_page_table_allocator(&(comm->w3b_cpt_alloc_context)); - - internal_vfree((void *)comm->w3b); - comm->w3b = 0; - comm->w3b_shmem_size = 0; - clear_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags)); -} - - -/* - * Allocates the W3B buffer for the specified comm. - * Returns zero upon successful completion, or an appropriate error code upon - * failure. - */ -static inline int tf_allocate_w3b(struct tf_comm *comm) -{ - int error; - u32 flags; - u32 config_flag_s; - u32 *w3b_descriptors; - u32 w3b_descriptor_count; - u32 w3b_current_size; - - config_flag_s = tf_read_reg32(&comm->l1_buffer->config_flag_s); - -retry: - if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags))) == 0) { - /* - * Initialize the shared memory for the W3B - */ - tf_init_coarse_page_table_allocator( - &comm->w3b_cpt_alloc_context); - } else { - /* - * The W3B is allocated but do we have to reallocate a bigger - * one? - */ - /* Check H bit */ - if ((config_flag_s & (1<<4)) != 0) { - /* The size of the W3B may change after SMC_INIT */ - /* Read the current value */ - w3b_current_size = tf_read_reg32( - &comm->l1_buffer->w3b_size_current_s); - if (comm->w3b_shmem_size > w3b_current_size) - return 0; - - tf_free_w3b(comm); - goto retry; - } else { - return 0; - } - } - - /* check H bit */ - if ((config_flag_s & (1<<4)) != 0) - /* The size of the W3B may change after SMC_INIT */ - /* Read the current value */ - comm->w3b_shmem_size = tf_read_reg32( - &comm->l1_buffer->w3b_size_current_s); - else - comm->w3b_shmem_size = tf_read_reg32( - &comm->l1_buffer->w3b_size_max_s); - - comm->w3b = (u32) internal_vmalloc(comm->w3b_shmem_size); - if (comm->w3b == 0) { - printk(KERN_ERR "tf_allocate_w3b():" - " Out of memory for W3B buffer (%u bytes)!\n", - (unsigned int)(comm->w3b_shmem_size)); - error = -ENOMEM; - goto error; - } - - /* initialize the w3b_shmem_desc structure */ - comm->w3b_shmem_desc.type = TF_SHMEM_TYPE_PM_HIBERNATE; - INIT_LIST_HEAD(&(comm->w3b_shmem_desc.list)); - - flags = (TF_SHMEM_TYPE_READ | TF_SHMEM_TYPE_WRITE); - - /* directly point to the L1 shared buffer W3B descriptors */ - w3b_descriptors = comm->l1_buffer->w3b_descriptors; - - /* - * tf_fill_descriptor_table uses the following parameter as an - * IN/OUT - */ - - error = tf_fill_descriptor_table( - &(comm->w3b_cpt_alloc_context), - &(comm->w3b_shmem_desc), - comm->w3b, - NULL, - w3b_descriptors, - comm->w3b_shmem_size, - &(comm->w3b_shmem_offset), - false, - flags, - &w3b_descriptor_count); - if (error != 0) { - printk(KERN_ERR "tf_allocate_w3b():" - " tf_fill_descriptor_table failed with " - "error code 0x%08x!\n", - error); - goto error; - } - - set_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags)); - - /* successful completion */ - return 0; - -error: - tf_free_w3b(comm); - - return error; -} - -/* - * Perform a Secure World shutdown operation. - * The routine does not return if the operation succeeds. - * the routine returns an appropriate error code if - * the operation fails. - */ -int tf_pm_shutdown(struct tf_comm *comm) -{ -#ifdef CONFIG_TFN - /* this function is useless for the TEGRA product */ - return 0; -#else - int error; - union tf_command command; - union tf_answer answer; - - dprintk(KERN_INFO "tf_pm_shutdown()\n"); - - memset(&command, 0, sizeof(command)); - - command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; - command.header.message_size = - (sizeof(struct tf_command_management) - - sizeof(struct tf_command_header))/sizeof(u32); - - command.management.command = TF_MANAGEMENT_SHUTDOWN; - - error = tf_send_receive( - comm, - &command, - &answer, - NULL, - false); - - if (error != 0) { - dprintk(KERN_ERR "tf_pm_shutdown(): " - "tf_send_receive failed (error %d)!\n", - error); - return error; - } - -#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT - if (answer.header.error_code != 0) - dprintk(KERN_ERR "tf_driver: shutdown failed.\n"); - else - dprintk(KERN_INFO "tf_driver: shutdown succeeded.\n"); -#endif - - return answer.header.error_code; -#endif -} - - -/* - * Perform a Secure World hibernate operation. - * The routine does not return if the operation succeeds. - * the routine returns an appropriate error code if - * the operation fails. - */ -int tf_pm_hibernate(struct tf_comm *comm) -{ -#ifdef CONFIG_TFN - /* this function is useless for the TEGRA product */ - return 0; -#else - int error; - union tf_command command; - union tf_answer answer; - u32 first_command; - u32 first_free_command; - - dprintk(KERN_INFO "tf_pm_hibernate()\n"); - - error = tf_allocate_w3b(comm); - if (error != 0) { - dprintk(KERN_ERR "tf_pm_hibernate(): " - "tf_allocate_w3b failed (error %d)!\n", - error); - return error; - } - - /* - * As the polling thread is already hibernating, we - * should send the message and receive the answer ourself - */ - - /* build the "prepare to hibernate" message */ - command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; - command.management.command = TF_MANAGEMENT_HIBERNATE; - /* Long Form Command */ - command.management.shared_mem_descriptors[0] = 0; - command.management.shared_mem_descriptors[1] = 0; - command.management.w3b_size = - comm->w3b_shmem_size | 0x80000000; - command.management.w3b_start_offset = - comm->w3b_shmem_offset; - command.header.operation_id = (u32) &answer; - - tf_dump_command(&command); - - /* find a slot to send the message in */ - - /* AFY: why not use the function tf_send_receive?? We are - * duplicating a lot of subtle code here. And it's not going to be - * tested because power management is currently not supported by the - * secure world. */ - for (;;) { - int queue_words_count, command_size; - - spin_lock(&(comm->lock)); - - first_command = tf_read_reg32( - &comm->l1_buffer->first_command); - first_free_command = tf_read_reg32( - &comm->l1_buffer->first_free_command); - - queue_words_count = first_free_command - first_command; - command_size = command.header.message_size - + sizeof(struct tf_command_header); - if ((queue_words_count + command_size) < - TF_N_MESSAGE_QUEUE_CAPACITY) { - /* Command queue is not full */ - memcpy(&comm->l1_buffer->command_queue[ - first_free_command % - TF_N_MESSAGE_QUEUE_CAPACITY], - &command, - command_size * sizeof(u32)); - - tf_write_reg32(&comm->l1_buffer->first_free_command, - first_free_command + command_size); - - spin_unlock(&(comm->lock)); - break; - } - - spin_unlock(&(comm->lock)); - (void)tf_schedule_secure_world(comm); - } - - /* now wait for the answer, dispatching other answers */ - while (1) { - u32 first_answer; - u32 first_free_answer; - - /* check all the answers */ - first_free_answer = tf_read_reg32( - &comm->l1_buffer->first_free_answer); - first_answer = tf_read_reg32( - &comm->l1_buffer->first_answer); - - if (first_answer != first_free_answer) { - int bFoundAnswer = 0; - - do { - /* answer queue not empty */ - union tf_answer tmp_answer; - struct tf_answer_header header; - /* size of the command in words of 32bit */ - int command_size; - - /* get the message_size */ - memcpy(&header, - &comm->l1_buffer->answer_queue[ - first_answer % - TF_S_ANSWER_QUEUE_CAPACITY], - sizeof(struct tf_answer_header)); - command_size = header.message_size + - sizeof(struct tf_answer_header); - - /* - * NOTE: message_size is the number of words - * following the first word - */ - memcpy(&tmp_answer, - &comm->l1_buffer->answer_queue[ - first_answer % - TF_S_ANSWER_QUEUE_CAPACITY], - command_size * sizeof(u32)); - - tf_dump_answer(&tmp_answer); - - if (tmp_answer.header.operation_id == - (u32) &answer) { - /* - * this is the answer to the "prepare to - * hibernate" message - */ - memcpy(&answer, - &tmp_answer, - command_size * sizeof(u32)); - - bFoundAnswer = 1; - tf_write_reg32( - &comm->l1_buffer->first_answer, - first_answer + command_size); - break; - } else { - /* - * this is a standard message answer, - * dispatch it - */ - struct tf_answer_struct - *answerStructure; - - answerStructure = - (struct tf_answer_struct *) - tmp_answer.header.operation_id; - - memcpy(answerStructure->answer, - &tmp_answer, - command_size * sizeof(u32)); - - answerStructure->answer_copied = true; - } - - tf_write_reg32( - &comm->l1_buffer->first_answer, - first_answer + command_size); - } while (first_answer != first_free_answer); - - if (bFoundAnswer) - break; - } - - /* - * since the Secure World is at least running the "prepare to - * hibernate" message, its timeout must be immediate So there is - * no need to check its timeout and schedule() the current - * thread - */ - (void)tf_schedule_secure_world(comm); - } /* while (1) */ - - printk(KERN_INFO "tf_driver: hibernate.\n"); - return 0; -#endif -} - - -/* - * Perform a Secure World resume operation. - * The routine returns once the Secure World is active again - * or if an error occurs during the "resume" process - */ -int tf_pm_resume(struct tf_comm *comm) -{ -#ifdef CONFIG_TFN - /* this function is useless for the TEGRA product */ - return 0; -#else - int error; - u32 status; - - dprintk(KERN_INFO "tf_pm_resume()\n"); - - error = tf_smc_wake_up( - tf_get_l2init_descriptor((u32)comm->l1_buffer), - comm->w3b_shmem_offset, - comm->w3b_shmem_size); - - if (error != 0) { - dprintk(KERN_ERR "tf_pm_resume(): " - "tf_smc_wake_up failed (error %d)!\n", - error); - return error; - } - - status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) - & TF_STATUS_POWER_STATE_MASK) - >> TF_STATUS_POWER_STATE_SHIFT); - - while ((status != TF_POWER_MODE_ACTIVE) - && (status != TF_POWER_MODE_PANIC)) { - tf_smc_nyield(); - - status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) - & TF_STATUS_POWER_STATE_MASK) - >> TF_STATUS_POWER_STATE_SHIFT); - - /* - * As this may last quite a while, call the kernel scheduler to - * hand over CPU for other operations - */ - schedule(); - } - - switch (status) { - case TF_POWER_MODE_ACTIVE: - break; - - case TF_POWER_MODE_PANIC: - dprintk(KERN_ERR "tf_pm_resume(): " - "Secure World POWER_MODE_PANIC!\n"); - return -EINVAL; - - default: - dprintk(KERN_ERR "tf_pm_resume(): " - "unexpected Secure World POWER_MODE (%d)!\n", status); - return -EINVAL; - } - - dprintk(KERN_INFO "tf_pm_resume() succeeded\n"); - return 0; -#endif -} - -/*---------------------------------------------------------------------------- - * Communication initialization and termination - *----------------------------------------------------------------------------*/ - -/* - * Handles the software interrupts issued by the Secure World. - */ -static irqreturn_t tf_soft_int_handler(int irq, void *dev_id) -{ - struct tf_comm *comm = (struct tf_comm *) dev_id; - - if (comm->l1_buffer == NULL) - return IRQ_NONE; - - if ((tf_read_reg32(&comm->l1_buffer->status_s) & - TF_STATUS_P_MASK) == 0) - /* interrupt not issued by the Trusted Foundations Software */ - return IRQ_NONE; - - tf_smc_reset_irq(); - - /* signal N_SM_EVENT */ - wake_up(&comm->wait_queue); - - return IRQ_HANDLED; -} - -/* - * Initializes the communication with the Secure World. - * The L1 shared buffer is allocated and the Secure World - * is yielded for the first time. - * returns successfuly once the communication with - * the Secure World is up and running - * - * Returns 0 upon success or appropriate error code - * upon failure - */ -int tf_init(struct tf_comm *comm) -{ - int error; - struct page *buffer_page; - u32 protocol_version; - - dprintk(KERN_INFO "tf_init()\n"); - - spin_lock_init(&(comm->lock)); - comm->flags = 0; - comm->l1_buffer = NULL; - init_waitqueue_head(&(comm->wait_queue)); - - /* - * Check the Secure World protocol version is the expected one. - */ - tf_smc_get_protocol_version(&protocol_version); - - if ((GET_PROTOCOL_MAJOR_VERSION(protocol_version)) - != TF_S_PROTOCOL_MAJOR_VERSION) { - printk(KERN_ERR "tf_init():" - " Unsupported Secure World Major Version " - "(0x%02X, expected 0x%02X)!\n", - GET_PROTOCOL_MAJOR_VERSION(protocol_version), - TF_S_PROTOCOL_MAJOR_VERSION); - error = -EIO; - goto error; - } - - /* - * Register the software interrupt handler if required to. - */ - if (comm->soft_int_irq != -1) { - dprintk(KERN_INFO "tf_init(): " - "Registering software interrupt handler (IRQ %d)\n", - comm->soft_int_irq); - - error = request_irq(comm->soft_int_irq, - tf_soft_int_handler, - IRQF_SHARED, - TF_DEVICE_BASE_NAME, - comm); - if (error != 0) { - dprintk(KERN_ERR "tf_init(): " - "request_irq failed for irq %d (error %d)\n", - comm->soft_int_irq, error); - goto error; - } - set_bit(TF_COMM_FLAG_IRQ_REQUESTED, &(comm->flags)); - } - - /* - * Allocate and initialize the L1 shared buffer. - */ - comm->l1_buffer = (void *) internal_get_zeroed_page(GFP_KERNEL); - if (comm->l1_buffer == NULL) { - printk(KERN_ERR "tf_init():" - " get_zeroed_page failed for L1 shared buffer!\n"); - error = -ENOMEM; - goto error; - } - - /* - * Ensure the page storing the L1 shared buffer is mapped. - */ - buffer_page = virt_to_page(comm->l1_buffer); - trylock_page(buffer_page); - - dprintk(KERN_INFO "tf_init(): " - "L1 shared buffer allocated at virtual:%p, " - "physical:%p (page:%p)\n", - comm->l1_buffer, - (void *)virt_to_phys(comm->l1_buffer), - buffer_page); - - set_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags)); - - /* - * Init SMC - */ - error = tf_smc_init( - tf_get_l2init_descriptor((u32)comm->l1_buffer)); - if (error != S_SUCCESS) { - dprintk(KERN_ERR "tf_init(): " - "tf_smc_init failed (error 0x%08X)!\n", - error); - goto error; - } - - /* - * check whether the interrupts are actually enabled - * If not, remove irq handler - */ - if ((tf_read_reg32(&comm->l1_buffer->config_flag_s) & - TF_CONFIG_FLAG_S) == 0) { - if (test_and_clear_bit(TF_COMM_FLAG_IRQ_REQUESTED, - &(comm->flags)) != 0) { - dprintk(KERN_INFO "tf_init(): " - "Interrupts not used, unregistering " - "softint (IRQ %d)\n", - comm->soft_int_irq); - - free_irq(comm->soft_int_irq, comm); - } - } else { - if (test_bit(TF_COMM_FLAG_IRQ_REQUESTED, - &(comm->flags)) == 0) { - /* - * Interrupts are enabled in the Secure World, but not - * handled by driver - */ - dprintk(KERN_ERR "tf_init(): " - "soft_interrupt argument not provided\n"); - error = -EINVAL; - goto error; - } - } - - /* - * Successful completion. - */ - - /* yield for the first time */ - (void)tf_schedule_secure_world(comm); - - dprintk(KERN_INFO "tf_init(): Success\n"); - return S_SUCCESS; - -error: - /* - * Error handling. - */ - dprintk(KERN_INFO "tf_init(): Failure (error %d)\n", - error); - tf_terminate(comm); - return error; -} - - -/* - * Attempt to terminate the communication with the Secure World. - * The L1 shared buffer is freed. - * Calling this routine terminates definitaly the communication - * with the Secure World : there is no way to inform the Secure World of a new - * L1 shared buffer to be used once it has been initialized. - */ -void tf_terminate(struct tf_comm *comm) -{ - dprintk(KERN_INFO "tf_terminate()\n"); - - set_bit(TF_COMM_FLAG_TERMINATING, &(comm->flags)); - - if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, - &(comm->flags))) != 0) { - dprintk(KERN_INFO "tf_terminate(): " - "Freeing the W3B buffer...\n"); - tf_free_w3b(comm); - } - - if ((test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, - &(comm->flags))) != 0) { - __clear_page_locked(virt_to_page(comm->l1_buffer)); - internal_free_page((unsigned long) comm->l1_buffer); - } - - if ((test_bit(TF_COMM_FLAG_IRQ_REQUESTED, - &(comm->flags))) != 0) { - dprintk(KERN_INFO "tf_terminate(): " - "Unregistering softint (IRQ %d)\n", - comm->soft_int_irq); - free_irq(comm->soft_int_irq, comm); - } -} |