|  | /* | 
|  | * Copyright (C) 2010-2016 ARM Limited. All rights reserved. | 
|  | * | 
|  | * This program is free software and is provided to you under the terms of the GNU General Public License version 2 | 
|  | * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. | 
|  | * | 
|  | * A copy of the licence is included with the program, and can also be obtained from Free Software | 
|  | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
|  | */ | 
|  |  | 
|  | #include "mali_kernel_common.h" | 
|  | #include "mali_memory.h" | 
|  | #include "mali_memory_secure.h" | 
|  | #include "mali_osk.h" | 
|  | #include <linux/mutex.h> | 
|  | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) | 
|  | #include <linux/dma-direct.h> | 
|  | #else | 
|  | #include <linux/dma-mapping.h> | 
|  | #endif | 
|  | #include <linux/dma-buf.h> | 
|  |  | 
|  | _mali_osk_errcode_t mali_mem_secure_attach_dma_buf(mali_mem_secure *secure_mem, u32 size, int mem_fd) | 
|  | { | 
|  | struct dma_buf *buf; | 
|  | MALI_DEBUG_ASSERT_POINTER(secure_mem); | 
|  |  | 
|  | /* get dma buffer */ | 
|  | buf = dma_buf_get(mem_fd); | 
|  | if (IS_ERR_OR_NULL(buf)) { | 
|  | MALI_DEBUG_PRINT_ERROR(("Failed to get dma buf!\n")); | 
|  | return _MALI_OSK_ERR_FAULT; | 
|  | } | 
|  |  | 
|  | if (size != buf->size) { | 
|  | MALI_DEBUG_PRINT_ERROR(("The secure mem size not match to the dma buf size!\n")); | 
|  | goto failed_alloc_mem; | 
|  | } | 
|  |  | 
|  | secure_mem->buf =  buf; | 
|  | secure_mem->attachment = dma_buf_attach(secure_mem->buf, &mali_platform_device->dev); | 
|  | if (NULL == secure_mem->attachment) { | 
|  | MALI_DEBUG_PRINT_ERROR(("Failed to get dma buf attachment!\n")); | 
|  | goto failed_dma_attach; | 
|  | } | 
|  |  | 
|  | secure_mem->sgt = dma_buf_map_attachment(secure_mem->attachment, DMA_BIDIRECTIONAL); | 
|  | if (IS_ERR_OR_NULL(secure_mem->sgt)) { | 
|  | MALI_DEBUG_PRINT_ERROR(("Failed to map dma buf attachment\n")); | 
|  | goto  failed_dma_map; | 
|  | } | 
|  |  | 
|  | secure_mem->count = size / MALI_MMU_PAGE_SIZE; | 
|  |  | 
|  | return _MALI_OSK_ERR_OK; | 
|  |  | 
|  | failed_dma_map: | 
|  | dma_buf_detach(secure_mem->buf, secure_mem->attachment); | 
|  | failed_dma_attach: | 
|  | failed_alloc_mem: | 
|  | dma_buf_put(buf); | 
|  | return _MALI_OSK_ERR_FAULT; | 
|  | } | 
|  |  | 
|  | _mali_osk_errcode_t mali_mem_secure_mali_map(mali_mem_secure *secure_mem, struct mali_session_data *session, u32 vaddr, u32 props) | 
|  | { | 
|  | struct mali_page_directory *pagedir; | 
|  | struct scatterlist *sg; | 
|  | u32 virt = vaddr; | 
|  | u32 prop = props; | 
|  | int i; | 
|  |  | 
|  | MALI_DEBUG_ASSERT_POINTER(secure_mem); | 
|  | MALI_DEBUG_ASSERT_POINTER(secure_mem->sgt); | 
|  | MALI_DEBUG_ASSERT_POINTER(session); | 
|  |  | 
|  | pagedir = session->page_directory; | 
|  |  | 
|  | for_each_sg(secure_mem->sgt->sgl, sg, secure_mem->sgt->nents, i) { | 
|  | u32 size = sg_dma_len(sg); | 
|  | dma_addr_t phys = sg_dma_address(sg); | 
|  |  | 
|  | /* sg must be page aligned. */ | 
|  | MALI_DEBUG_ASSERT(0 == size % MALI_MMU_PAGE_SIZE); | 
|  | MALI_DEBUG_ASSERT(0 == (phys & ~(uintptr_t)0xFFFFFFFF)); | 
|  |  | 
|  | mali_mmu_pagedir_update(pagedir, virt, phys, size, prop); | 
|  |  | 
|  | MALI_DEBUG_PRINT(3, ("The secure mem physical address: 0x%x gpu virtual address: 0x%x! \n", phys, virt)); | 
|  | virt += size; | 
|  | } | 
|  |  | 
|  | return _MALI_OSK_ERR_OK; | 
|  | } | 
|  |  | 
|  | void mali_mem_secure_mali_unmap(mali_mem_allocation *alloc) | 
|  | { | 
|  | struct mali_session_data *session; | 
|  | MALI_DEBUG_ASSERT_POINTER(alloc); | 
|  | session = alloc->session; | 
|  | MALI_DEBUG_ASSERT_POINTER(session); | 
|  |  | 
|  | mali_session_memory_lock(session); | 
|  | mali_mem_mali_map_free(session, alloc->psize, alloc->mali_vma_node.vm_node.start, | 
|  | alloc->flags); | 
|  | mali_session_memory_unlock(session); | 
|  | } | 
|  |  | 
|  |  | 
|  | int mali_mem_secure_cpu_map(mali_mem_backend *mem_bkend, struct vm_area_struct *vma) | 
|  | { | 
|  |  | 
|  | int ret = 0; | 
|  | struct scatterlist *sg; | 
|  | mali_mem_secure *secure_mem = &mem_bkend->secure_mem; | 
|  | unsigned long addr = vma->vm_start; | 
|  | int i; | 
|  |  | 
|  | MALI_DEBUG_ASSERT(mem_bkend->type == MALI_MEM_SECURE); | 
|  |  | 
|  | for_each_sg(secure_mem->sgt->sgl, sg, secure_mem->sgt->nents, i) { | 
|  | phys_addr_t phys; | 
|  | dma_addr_t dev_addr; | 
|  | u32 size, j; | 
|  | dev_addr = sg_dma_address(sg); | 
|  | #if defined(CONFIG_ARM64) ||LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) | 
|  | phys =  dma_to_phys(&mali_platform_device->dev, dev_addr); | 
|  | #else | 
|  | phys = page_to_phys(pfn_to_page(dma_to_pfn(&mali_platform_device->dev, dev_addr))); | 
|  | #endif | 
|  | size = sg_dma_len(sg); | 
|  | MALI_DEBUG_ASSERT(0 == size % _MALI_OSK_MALI_PAGE_SIZE); | 
|  |  | 
|  | for (j = 0; j < size / _MALI_OSK_MALI_PAGE_SIZE; j++) { | 
|  | ret = vm_insert_pfn(vma, addr, PFN_DOWN(phys)); | 
|  |  | 
|  | if (unlikely(0 != ret)) { | 
|  | return -EFAULT; | 
|  | } | 
|  | addr += _MALI_OSK_MALI_PAGE_SIZE; | 
|  | phys += _MALI_OSK_MALI_PAGE_SIZE; | 
|  |  | 
|  | MALI_DEBUG_PRINT(3, ("The secure mem physical address: 0x%x , cpu virtual address: 0x%x! \n", phys, addr)); | 
|  | } | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | u32 mali_mem_secure_release(mali_mem_backend *mem_bkend) | 
|  | { | 
|  | struct mali_mem_secure *mem; | 
|  | mali_mem_allocation *alloc = mem_bkend->mali_allocation; | 
|  | u32 free_pages_nr = 0; | 
|  | MALI_DEBUG_ASSERT(mem_bkend->type == MALI_MEM_SECURE); | 
|  |  | 
|  | mem = &mem_bkend->secure_mem; | 
|  | MALI_DEBUG_ASSERT_POINTER(mem->attachment); | 
|  | MALI_DEBUG_ASSERT_POINTER(mem->buf); | 
|  | MALI_DEBUG_ASSERT_POINTER(mem->sgt); | 
|  | /* Unmap the memory from the mali virtual address space. */ | 
|  | mali_mem_secure_mali_unmap(alloc); | 
|  | mutex_lock(&mem_bkend->mutex); | 
|  | dma_buf_unmap_attachment(mem->attachment, mem->sgt, DMA_BIDIRECTIONAL); | 
|  | dma_buf_detach(mem->buf, mem->attachment); | 
|  | dma_buf_put(mem->buf); | 
|  | mutex_unlock(&mem_bkend->mutex); | 
|  |  | 
|  | free_pages_nr = mem->count; | 
|  |  | 
|  | return free_pages_nr; | 
|  | } | 
|  |  | 
|  |  |