1 /*
2 * The MIT License (MIT)
3 *
4 * COPYRIGHT (C) 2017 Institute of Electronics and Computer Science (EDI), Latvia.
5 * AUTHOR: Rihards Novickis (rihards.novickis@edi.lv)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 */
26
27 /*!
28 * Copyright (c) 2018 by Contributors
29 * \file cma_api.cc
30 * \brief Application layer implementation for contigous memory allocation.
31 */
32
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/ioctl.h>
39 #include <sys/mman.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42
43 #include "cma_api.h"
44
45 #ifndef CMA_IOCTL_MAGIC
46 #define CMA_IOCTL_MAGIC 0xf2
47 #endif
48
49 #define CMA_ALLOC_CACHED _IOC(_IOC_WRITE | _IOC_READ, CMA_IOCTL_MAGIC, 1, 4)
50 #define CMA_ALLOC_NONCACHED _IOC(_IOC_WRITE | _IOC_READ, CMA_IOCTL_MAGIC, 2, 4)
51 #define CMA_FREE _IOC(_IOC_WRITE, CMA_IOCTL_MAGIC, 3, 4)
52 #define CMA_GET_PHY_ADDR _IOC(_IOC_WRITE | _IOC_READ, CMA_IOCTL_MAGIC, 4, 4)
53 #define CMA_GET_SIZE _IOC(_IOC_WRITE | _IOC_READ, CMA_IOCTL_MAGIC, 5, 4)
54
55 #define CMA_IOCTL_MAXNR 5
56
57 #ifndef CMA_DEBUG
58 #define CMA_DEBUG 0
59 #endif
60 #ifndef DRIVER_NODE_NAME
61 #define DRIVER_NODE_NAME "cma"
62 #endif
63
64 #if CMA_DEBUG == 1
65 #define __DEBUG(fmt, args...) printf("CMA_API_DEBUG: " fmt, ##args)
66 #else
67 #define __DEBUG(fmt, args...)
68 #endif
69
70 #define ROUND_UP(N, S) ((((N) + (S)-1) / (S)) * (S))
71
72 /* Private functions */
73 void* cma_alloc(size_t size, unsigned ioctl_cmd);
74
75 /* Global file descriptor */
76 int cma_fd = 0;
77
cma_init(void)78 int cma_init(void) {
79 __DEBUG("Opening \"/dev/" DRIVER_NODE_NAME "\" file\n");
80
81 cma_fd = open("/dev/" DRIVER_NODE_NAME, O_RDWR);
82 if (cma_fd == -1) {
83 __DEBUG("Failed to initialize api - \"%s\"\n", strerror(errno));
84 return -1;
85 }
86
87 return 0;
88 }
89
cma_release(void)90 int cma_release(void) {
91 __DEBUG("Closing \"/dev/" DRIVER_NODE_NAME "\" file\n");
92
93 if (close(cma_fd) == -1) {
94 __DEBUG("Failed to finilize api - \"%s\"\n", strerror(errno));
95 return -1;
96 }
97
98 return 0;
99 }
100
cma_alloc_cached(size_t size)101 void* cma_alloc_cached(size_t size) { return cma_alloc(size, CMA_ALLOC_CACHED); }
102
cma_alloc_noncached(size_t size)103 void* cma_alloc_noncached(size_t size) { return cma_alloc(size, CMA_ALLOC_NONCACHED); }
104
cma_free(void * mem)105 int cma_free(void* mem) {
106 __DEBUG("Releasing contigous memory from 0x%x\n", (unsigned)mem);
107 unsigned data, v_addr;
108
109 /* save user space pointer value */
110 data = (unsigned)mem;
111 v_addr = (unsigned)mem;
112
113 if (ioctl(cma_fd, CMA_GET_SIZE, &data) == -1) {
114 __DEBUG("cma_free - ioctl command unsuccsessful - 0\n");
115 return -1;
116 }
117 /* data now contains size */
118
119 /* unmap memory */
120 munmap(mem, data);
121
122 /* free cma entry */
123 if (ioctl(cma_fd, CMA_FREE, &v_addr) == -1) {
124 __DEBUG("cma_free - ioctl command unsuccsessful - 1\n");
125 return -1;
126 }
127
128 return 0;
129 }
130
cma_get_phy_addr(void * mem)131 unsigned cma_get_phy_addr(void* mem) {
132 unsigned data;
133 __DEBUG("Getting physical address from 0x%x\n", (unsigned)mem);
134
135 /* save user space pointer value */
136 data = (unsigned)mem;
137
138 /* get physical address */
139 if (ioctl(cma_fd, CMA_GET_PHY_ADDR, &data) == -1) {
140 __DEBUG("cma_free - ioctl command unsuccsessful\n");
141 return 0;
142 }
143 /* data now contains physical address */
144
145 return data;
146 }
147
cma_alloc(size_t size,unsigned ioctl_cmd)148 void* cma_alloc(size_t size, unsigned ioctl_cmd) {
149 unsigned data;
150 void* mem;
151 __DEBUG("Allocating 0x%x bytes of contigous memory\n", size);
152
153 /* Page align size */
154 size = ROUND_UP(size, getpagesize());
155
156 /* ioctl cmd to allocate contigous memory */
157 data = (unsigned)size;
158 if (ioctl(cma_fd, ioctl_cmd, &data) == -1) {
159 __DEBUG("cma_alloc - ioctl command unsuccsessful\n");
160 return NULL;
161 }
162
163 /* at this point phy_addr is written to data */
164
165 /* mmap memory */
166 mem = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, cma_fd, data);
167 if (mem == MAP_FAILED) {
168 __DEBUG("cma_alloc - mmap unsuccsessful\n");
169 return NULL;
170 }
171
172 return mem;
173 }
174