UPSTREAM: DT/arm,gic-v3: Documment PPI partition support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / ump / common / ump_kernel_ref_drv.c
1 /*
2  * Copyright (C) 2010-2014 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 #include "mali_osk.h"
12 #include "mali_osk_list.h"
13 #include "ump_osk.h"
14 #include "ump_uk_types.h"
15
16 #include "ump_kernel_interface_ref_drv.h"
17 #include "ump_kernel_common.h"
18 #include "ump_kernel_descriptor_mapping.h"
19
20 #define UMP_MINIMUM_SIZE         4096
21 #define UMP_MINIMUM_SIZE_MASK    (~(UMP_MINIMUM_SIZE-1))
22 #define UMP_SIZE_ALIGN(x)        (((x)+UMP_MINIMUM_SIZE-1)&UMP_MINIMUM_SIZE_MASK)
23 #define UMP_ADDR_ALIGN_OFFSET(x) ((x)&(UMP_MINIMUM_SIZE-1))
24 static void phys_blocks_release(void *ctx, struct ump_dd_mem *descriptor);
25
26 UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block *blocks, unsigned long num_blocks)
27 {
28         ump_dd_mem *mem;
29         unsigned long size_total = 0;
30         int ret;
31         u32 i;
32
33         /* Go through the input blocks and verify that they are sane */
34         for (i = 0; i < num_blocks; i++) {
35                 unsigned long addr = blocks[i].addr;
36                 unsigned long size = blocks[i].size;
37
38                 DBG_MSG(5, ("Adding physical memory to new handle. Address: 0x%08lx, size: %lu\n", addr, size));
39                 size_total += blocks[i].size;
40
41                 if (0 != UMP_ADDR_ALIGN_OFFSET(addr)) {
42                         MSG_ERR(("Trying to create UMP memory from unaligned physical address. Address: 0x%08lx\n", addr));
43                         return UMP_DD_HANDLE_INVALID;
44                 }
45
46                 if (0 != UMP_ADDR_ALIGN_OFFSET(size)) {
47                         MSG_ERR(("Trying to create UMP memory with unaligned size. Size: %lu\n", size));
48                         return UMP_DD_HANDLE_INVALID;
49                 }
50         }
51
52         /* Allocate the ump_dd_mem struct for this allocation */
53         mem = _mali_osk_malloc(sizeof(*mem));
54         if (NULL == mem) {
55                 DBG_MSG(1, ("Could not allocate ump_dd_mem in ump_dd_handle_create_from_phys_blocks()\n"));
56                 return UMP_DD_HANDLE_INVALID;
57         }
58
59         /* Now, make a copy of the block information supplied by the user */
60         mem->block_array = _mali_osk_malloc(sizeof(ump_dd_physical_block) * num_blocks);
61         if (NULL == mem->block_array) {
62                 _mali_osk_free(mem);
63                 DBG_MSG(1, ("Could not allocate a mem handle for function ump_dd_handle_create_from_phys_blocks().\n"));
64                 return UMP_DD_HANDLE_INVALID;
65         }
66
67         _mali_osk_memcpy(mem->block_array, blocks, sizeof(ump_dd_physical_block) * num_blocks);
68
69         /* And setup the rest of the ump_dd_mem struct */
70         _mali_osk_atomic_init(&mem->ref_count, 1);
71         mem->size_bytes = size_total;
72         mem->nr_blocks = num_blocks;
73         mem->backend_info = NULL;
74         mem->ctx = NULL;
75         mem->release_func = phys_blocks_release;
76         /* For now UMP handles created by ump_dd_handle_create_from_phys_blocks() is forced to be Uncached */
77         mem->is_cached = 0;
78         mem->hw_device = _UMP_UK_USED_BY_CPU;
79         mem->lock_usage = UMP_NOT_LOCKED;
80
81         /* Find a secure ID for this allocation */
82         ret = ump_random_mapping_insert(device.secure_id_map, mem);
83         if (unlikely(ret)) {
84                 _mali_osk_free(mem->block_array);
85                 _mali_osk_free(mem);
86                 DBG_MSG(1, ("Failed to allocate secure ID in ump_dd_handle_create_from_phys_blocks()\n"));
87                 return UMP_DD_HANDLE_INVALID;
88         }
89
90         DBG_MSG(3, ("UMP memory created. ID: %u, size: %lu\n", mem->secure_id, mem->size_bytes));
91
92         return (ump_dd_handle)mem;
93 }
94
95 static void phys_blocks_release(void *ctx, struct ump_dd_mem *descriptor)
96 {
97         _mali_osk_free(descriptor->block_array);
98         descriptor->block_array = NULL;
99 }
100
101 _mali_osk_errcode_t _ump_ukk_allocate(_ump_uk_allocate_s *user_interaction)
102 {
103         ump_session_data *session_data = NULL;
104         ump_dd_mem *new_allocation = NULL;
105         ump_session_memory_list_element *session_memory_element = NULL;
106         int ret;
107
108         DEBUG_ASSERT_POINTER(user_interaction);
109         DEBUG_ASSERT_POINTER(user_interaction->ctx);
110
111         session_data = (ump_session_data *) user_interaction->ctx;
112
113         session_memory_element = _mali_osk_calloc(1, sizeof(ump_session_memory_list_element));
114         if (NULL == session_memory_element) {
115                 DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n"));
116                 return _MALI_OSK_ERR_NOMEM;
117         }
118
119
120         new_allocation = _mali_osk_calloc(1, sizeof(ump_dd_mem));
121         if (NULL == new_allocation) {
122                 _mali_osk_free(session_memory_element);
123                 DBG_MSG(1, ("Failed to allocate ump_dd_mem in _ump_ukk_allocate()\n"));
124                 return _MALI_OSK_ERR_NOMEM;
125         }
126
127         /* Initialize the part of the new_allocation that we know so for */
128         _mali_osk_atomic_init(&new_allocation->ref_count, 1);
129         if (0 == (UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE & user_interaction->constraints))
130                 new_allocation->is_cached = 0;
131         else new_allocation->is_cached = 1;
132
133         /* Special case a size of 0, we should try to emulate what malloc does
134          * in this case, which is to return a valid pointer that must be freed,
135          * but can't be dereferenced */
136         if (0 == user_interaction->size) {
137                 /* Emulate by actually allocating the minimum block size */
138                 user_interaction->size = 1;
139         }
140
141         /* Page align the size */
142         new_allocation->size_bytes = UMP_SIZE_ALIGN(user_interaction->size);
143         new_allocation->lock_usage = UMP_NOT_LOCKED;
144
145         /* Now, ask the active memory backend to do the actual memory allocation */
146         if (!device.backend->allocate(device.backend->ctx, new_allocation)) {
147                 DBG_MSG(3, ("OOM: No more UMP memory left. Failed to allocate memory in ump_ioctl_allocate(). Size: %lu, requested size: %lu\n",
148                             new_allocation->size_bytes,
149                             (unsigned long)user_interaction->size));
150                 _mali_osk_free(new_allocation);
151                 _mali_osk_free(session_memory_element);
152                 return _MALI_OSK_ERR_INVALID_FUNC;
153         }
154         new_allocation->hw_device = _UMP_UK_USED_BY_CPU;
155         new_allocation->ctx = device.backend->ctx;
156         new_allocation->release_func = device.backend->release;
157
158         /* Initialize the session_memory_element, and add it to the session object */
159         session_memory_element->mem = new_allocation;
160         _mali_osk_mutex_wait(session_data->lock);
161         _mali_osk_list_add(&(session_memory_element->list), &(session_data->list_head_session_memory_list));
162         _mali_osk_mutex_signal(session_data->lock);
163
164         /* Create a secure ID for this allocation */
165         ret = ump_random_mapping_insert(device.secure_id_map, new_allocation);
166         if (unlikely(ret)) {
167                 new_allocation->release_func(new_allocation->ctx, new_allocation);
168                 _mali_osk_free(session_memory_element);
169                 _mali_osk_free(new_allocation);
170                 DBG_MSG(1, ("Failed to allocate secure ID in ump_ioctl_allocate()\n"));
171                 return _MALI_OSK_ERR_INVALID_FUNC;
172         }
173
174         user_interaction->secure_id = new_allocation->secure_id;
175         user_interaction->size = new_allocation->size_bytes;
176         DBG_MSG(3, ("UMP memory allocated. ID: %u, size: %lu\n",
177                     new_allocation->secure_id,
178                     new_allocation->size_bytes));
179
180         return _MALI_OSK_ERR_OK;
181 }