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