1 /*- 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * BSD LICENSE 6 * 7 * Copyright 2011-2016 Freescale Semiconductor Inc. 8 * Copyright 2017 NXP. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are met: 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * * Neither the name of the above-listed copyright holders nor the 18 * names of any contributors may be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * GPL LICENSE SUMMARY 22 * 23 * ALTERNATIVELY, this software may be distributed under the terms of the 24 * GNU General Public License ("GPL") as published by the Free Software 25 * Foundation, either version 2 of that License or (at your option) any 26 * later version. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 #include <assert.h> 41 #include <fcntl.h> 42 #include <unistd.h> 43 #include <sys/ioctl.h> 44 45 #include "process.h" 46 47 #include <fsl_usd.h> 48 49 /* As higher-level drivers will be built on top of this (dma_mem, qbman, ...), 50 * it's preferable that the process driver itself not provide any exported API. 51 * As such, combined with the fact that none of these operations are 52 * performance critical, it is justified to use lazy initialisation, so that's 53 * what the lock is for. 54 */ 55 static int fd = -1; 56 static pthread_mutex_t fd_init_lock = PTHREAD_MUTEX_INITIALIZER; 57 58 static int check_fd(void) 59 { 60 int ret; 61 62 if (fd >= 0) 63 return 0; 64 ret = pthread_mutex_lock(&fd_init_lock); 65 assert(!ret); 66 /* check again with the lock held */ 67 if (fd < 0) 68 fd = open(PROCESS_PATH, O_RDWR); 69 ret = pthread_mutex_unlock(&fd_init_lock); 70 assert(!ret); 71 return (fd >= 0) ? 0 : -ENODEV; 72 } 73 74 #define DPAA_IOCTL_MAGIC 'u' 75 struct dpaa_ioctl_id_alloc { 76 uint32_t base; /* Return value, the start of the allocated range */ 77 enum dpaa_id_type id_type; /* what kind of resource(s) to allocate */ 78 uint32_t num; /* how many IDs to allocate (and return value) */ 79 uint32_t align; /* must be a power of 2, 0 is treated like 1 */ 80 int partial; /* whether to allow less than 'num' */ 81 }; 82 83 struct dpaa_ioctl_id_release { 84 /* Input; */ 85 enum dpaa_id_type id_type; 86 uint32_t base; 87 uint32_t num; 88 }; 89 90 struct dpaa_ioctl_id_reserve { 91 enum dpaa_id_type id_type; 92 uint32_t base; 93 uint32_t num; 94 }; 95 96 #define DPAA_IOCTL_ID_ALLOC \ 97 _IOWR(DPAA_IOCTL_MAGIC, 0x01, struct dpaa_ioctl_id_alloc) 98 #define DPAA_IOCTL_ID_RELEASE \ 99 _IOW(DPAA_IOCTL_MAGIC, 0x02, struct dpaa_ioctl_id_release) 100 #define DPAA_IOCTL_ID_RESERVE \ 101 _IOW(DPAA_IOCTL_MAGIC, 0x0A, struct dpaa_ioctl_id_reserve) 102 103 int process_alloc(enum dpaa_id_type id_type, uint32_t *base, uint32_t num, 104 uint32_t align, int partial) 105 { 106 struct dpaa_ioctl_id_alloc id = { 107 .id_type = id_type, 108 .num = num, 109 .align = align, 110 .partial = partial 111 }; 112 int ret = check_fd(); 113 114 if (ret) 115 return ret; 116 ret = ioctl(fd, DPAA_IOCTL_ID_ALLOC, &id); 117 if (ret) 118 return ret; 119 for (ret = 0; ret < (int)id.num; ret++) 120 base[ret] = id.base + ret; 121 return id.num; 122 } 123 124 void process_release(enum dpaa_id_type id_type, uint32_t base, uint32_t num) 125 { 126 struct dpaa_ioctl_id_release id = { 127 .id_type = id_type, 128 .base = base, 129 .num = num 130 }; 131 int ret = check_fd(); 132 133 if (ret) { 134 fprintf(stderr, "Process FD failure\n"); 135 return; 136 } 137 ret = ioctl(fd, DPAA_IOCTL_ID_RELEASE, &id); 138 if (ret) 139 fprintf(stderr, "Process FD ioctl failure type %d base 0x%x num %d\n", 140 id_type, base, num); 141 } 142 143 int process_reserve(enum dpaa_id_type id_type, uint32_t base, uint32_t num) 144 { 145 struct dpaa_ioctl_id_reserve id = { 146 .id_type = id_type, 147 .base = base, 148 .num = num 149 }; 150 int ret = check_fd(); 151 152 if (ret) 153 return ret; 154 return ioctl(fd, DPAA_IOCTL_ID_RESERVE, &id); 155 } 156 157 /***************************************/ 158 /* Mapping and using QMan/BMan portals */ 159 /***************************************/ 160 161 #define DPAA_IOCTL_PORTAL_MAP \ 162 _IOWR(DPAA_IOCTL_MAGIC, 0x07, struct dpaa_ioctl_portal_map) 163 #define DPAA_IOCTL_PORTAL_UNMAP \ 164 _IOW(DPAA_IOCTL_MAGIC, 0x08, struct dpaa_portal_map) 165 166 int process_portal_map(struct dpaa_ioctl_portal_map *params) 167 { 168 int ret = check_fd(); 169 170 if (ret) 171 return ret; 172 173 ret = ioctl(fd, DPAA_IOCTL_PORTAL_MAP, params); 174 if (ret) { 175 perror("ioctl(DPAA_IOCTL_PORTAL_MAP)"); 176 return ret; 177 } 178 return 0; 179 } 180 181 int process_portal_unmap(struct dpaa_portal_map *map) 182 { 183 int ret = check_fd(); 184 185 if (ret) 186 return ret; 187 188 ret = ioctl(fd, DPAA_IOCTL_PORTAL_UNMAP, map); 189 if (ret) { 190 perror("ioctl(DPAA_IOCTL_PORTAL_UNMAP)"); 191 return ret; 192 } 193 return 0; 194 } 195 196 #define DPAA_IOCTL_PORTAL_IRQ_MAP \ 197 _IOW(DPAA_IOCTL_MAGIC, 0x09, struct dpaa_ioctl_irq_map) 198 199 int process_portal_irq_map(int ifd, struct dpaa_ioctl_irq_map *map) 200 { 201 map->fd = fd; 202 return ioctl(ifd, DPAA_IOCTL_PORTAL_IRQ_MAP, map); 203 } 204 205 int process_portal_irq_unmap(int ifd) 206 { 207 return close(ifd); 208 } 209 210 struct dpaa_ioctl_raw_portal { 211 /* inputs */ 212 enum dpaa_portal_type type; /* Type of portal to allocate */ 213 214 uint8_t enable_stash; /* set to non zero to turn on stashing */ 215 /* Stashing attributes for the portal */ 216 uint32_t cpu; 217 uint32_t cache; 218 uint32_t window; 219 /* Specifies the stash request queue this portal should use */ 220 uint8_t sdest; 221 222 /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX 223 * for don't care. The portal index will be populated by the 224 * driver when the ioctl() successfully completes. 225 */ 226 uint32_t index; 227 228 /* outputs */ 229 uint64_t cinh; 230 uint64_t cena; 231 }; 232 233 #define DPAA_IOCTL_ALLOC_RAW_PORTAL \ 234 _IOWR(DPAA_IOCTL_MAGIC, 0x0C, struct dpaa_ioctl_raw_portal) 235 236 #define DPAA_IOCTL_FREE_RAW_PORTAL \ 237 _IOR(DPAA_IOCTL_MAGIC, 0x0D, struct dpaa_ioctl_raw_portal) 238 239 static int process_portal_allocate(struct dpaa_ioctl_raw_portal *portal) 240 { 241 int ret = check_fd(); 242 243 if (ret) 244 return ret; 245 246 ret = ioctl(fd, DPAA_IOCTL_ALLOC_RAW_PORTAL, portal); 247 if (ret) { 248 perror("ioctl(DPAA_IOCTL_ALLOC_RAW_PORTAL)"); 249 return ret; 250 } 251 return 0; 252 } 253 254 static int process_portal_free(struct dpaa_ioctl_raw_portal *portal) 255 { 256 int ret = check_fd(); 257 258 if (ret) 259 return ret; 260 261 ret = ioctl(fd, DPAA_IOCTL_FREE_RAW_PORTAL, portal); 262 if (ret) { 263 perror("ioctl(DPAA_IOCTL_FREE_RAW_PORTAL)"); 264 return ret; 265 } 266 return 0; 267 } 268 269 int qman_allocate_raw_portal(struct dpaa_raw_portal *portal) 270 { 271 struct dpaa_ioctl_raw_portal input; 272 int ret; 273 274 input.type = dpaa_portal_qman; 275 input.index = portal->index; 276 input.enable_stash = portal->enable_stash; 277 input.cpu = portal->cpu; 278 input.cache = portal->cache; 279 input.window = portal->window; 280 input.sdest = portal->sdest; 281 282 ret = process_portal_allocate(&input); 283 if (ret) 284 return ret; 285 portal->index = input.index; 286 portal->cinh = input.cinh; 287 portal->cena = input.cena; 288 return 0; 289 } 290 291 int qman_free_raw_portal(struct dpaa_raw_portal *portal) 292 { 293 struct dpaa_ioctl_raw_portal input; 294 295 input.type = dpaa_portal_qman; 296 input.index = portal->index; 297 input.cinh = portal->cinh; 298 input.cena = portal->cena; 299 300 return process_portal_free(&input); 301 } 302 303 int bman_allocate_raw_portal(struct dpaa_raw_portal *portal) 304 { 305 struct dpaa_ioctl_raw_portal input; 306 int ret; 307 308 input.type = dpaa_portal_bman; 309 input.index = portal->index; 310 input.enable_stash = 0; 311 312 ret = process_portal_allocate(&input); 313 if (ret) 314 return ret; 315 portal->index = input.index; 316 portal->cinh = input.cinh; 317 portal->cena = input.cena; 318 return 0; 319 } 320 321 int bman_free_raw_portal(struct dpaa_raw_portal *portal) 322 { 323 struct dpaa_ioctl_raw_portal input; 324 325 input.type = dpaa_portal_bman; 326 input.index = portal->index; 327 input.cinh = portal->cinh; 328 input.cena = portal->cena; 329 330 return process_portal_free(&input); 331 } 332