1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) 2 * 3 * Copyright 2011-2016 Freescale Semiconductor Inc. 4 * Copyright 2017,2020 NXP 5 * 6 */ 7 #include <assert.h> 8 #include <fcntl.h> 9 #include <unistd.h> 10 #include <sys/ioctl.h> 11 #include <rte_ethdev.h> 12 13 #include "process.h" 14 15 #include <fsl_usd.h> 16 17 /* As higher-level drivers will be built on top of this (dma_mem, qbman, ...), 18 * it's preferable that the process driver itself not provide any exported API. 19 * As such, combined with the fact that none of these operations are 20 * performance critical, it is justified to use lazy initialisation, so that's 21 * what the lock is for. 22 */ 23 static int fd = -1; 24 static pthread_mutex_t fd_init_lock = PTHREAD_MUTEX_INITIALIZER; 25 26 static int check_fd(void) 27 { 28 int ret; 29 30 if (fd >= 0) 31 return 0; 32 ret = pthread_mutex_lock(&fd_init_lock); 33 assert(!ret); 34 /* check again with the lock held */ 35 if (fd < 0) 36 fd = open(PROCESS_PATH, O_RDWR); 37 ret = pthread_mutex_unlock(&fd_init_lock); 38 assert(!ret); 39 return (fd >= 0) ? 0 : -ENODEV; 40 } 41 42 #define DPAA_IOCTL_MAGIC 'u' 43 struct dpaa_ioctl_id_alloc { 44 uint32_t base; /* Return value, the start of the allocated range */ 45 enum dpaa_id_type id_type; /* what kind of resource(s) to allocate */ 46 uint32_t num; /* how many IDs to allocate (and return value) */ 47 uint32_t align; /* must be a power of 2, 0 is treated like 1 */ 48 int partial; /* whether to allow less than 'num' */ 49 }; 50 51 struct dpaa_ioctl_id_release { 52 /* Input; */ 53 enum dpaa_id_type id_type; 54 uint32_t base; 55 uint32_t num; 56 }; 57 58 struct dpaa_ioctl_id_reserve { 59 enum dpaa_id_type id_type; 60 uint32_t base; 61 uint32_t num; 62 }; 63 64 #define DPAA_IOCTL_ID_ALLOC \ 65 _IOWR(DPAA_IOCTL_MAGIC, 0x01, struct dpaa_ioctl_id_alloc) 66 #define DPAA_IOCTL_ID_RELEASE \ 67 _IOW(DPAA_IOCTL_MAGIC, 0x02, struct dpaa_ioctl_id_release) 68 #define DPAA_IOCTL_ID_RESERVE \ 69 _IOW(DPAA_IOCTL_MAGIC, 0x0A, struct dpaa_ioctl_id_reserve) 70 71 int process_alloc(enum dpaa_id_type id_type, uint32_t *base, uint32_t num, 72 uint32_t align, int partial) 73 { 74 struct dpaa_ioctl_id_alloc id = { 75 .id_type = id_type, 76 .num = num, 77 .align = align, 78 .partial = partial 79 }; 80 int ret = check_fd(); 81 82 if (ret) 83 return ret; 84 ret = ioctl(fd, DPAA_IOCTL_ID_ALLOC, &id); 85 if (ret) 86 return ret; 87 for (ret = 0; ret < (int)id.num; ret++) 88 base[ret] = id.base + ret; 89 return id.num; 90 } 91 92 void process_release(enum dpaa_id_type id_type, uint32_t base, uint32_t num) 93 { 94 struct dpaa_ioctl_id_release id = { 95 .id_type = id_type, 96 .base = base, 97 .num = num 98 }; 99 int ret = check_fd(); 100 101 if (ret) { 102 fprintf(stderr, "Process FD failure\n"); 103 return; 104 } 105 ret = ioctl(fd, DPAA_IOCTL_ID_RELEASE, &id); 106 if (ret) 107 fprintf(stderr, "Process FD ioctl failure type %d base 0x%x num %d\n", 108 id_type, base, num); 109 } 110 111 int process_reserve(enum dpaa_id_type id_type, uint32_t base, uint32_t num) 112 { 113 struct dpaa_ioctl_id_reserve id = { 114 .id_type = id_type, 115 .base = base, 116 .num = num 117 }; 118 int ret = check_fd(); 119 120 if (ret) 121 return ret; 122 return ioctl(fd, DPAA_IOCTL_ID_RESERVE, &id); 123 } 124 125 /***************************************/ 126 /* Mapping and using QMan/BMan portals */ 127 /***************************************/ 128 129 #define DPAA_IOCTL_PORTAL_MAP \ 130 _IOWR(DPAA_IOCTL_MAGIC, 0x07, struct dpaa_ioctl_portal_map) 131 #define DPAA_IOCTL_PORTAL_UNMAP \ 132 _IOW(DPAA_IOCTL_MAGIC, 0x08, struct dpaa_portal_map) 133 134 int process_portal_map(struct dpaa_ioctl_portal_map *params) 135 { 136 int ret = check_fd(); 137 138 if (ret) 139 return ret; 140 141 ret = ioctl(fd, DPAA_IOCTL_PORTAL_MAP, params); 142 if (ret) { 143 perror("ioctl(DPAA_IOCTL_PORTAL_MAP)"); 144 return ret; 145 } 146 return 0; 147 } 148 149 int process_portal_unmap(struct dpaa_portal_map *map) 150 { 151 int ret = check_fd(); 152 153 if (ret) 154 return ret; 155 156 ret = ioctl(fd, DPAA_IOCTL_PORTAL_UNMAP, map); 157 if (ret) { 158 perror("ioctl(DPAA_IOCTL_PORTAL_UNMAP)"); 159 return ret; 160 } 161 return 0; 162 } 163 164 #define DPAA_IOCTL_PORTAL_IRQ_MAP \ 165 _IOW(DPAA_IOCTL_MAGIC, 0x09, struct dpaa_ioctl_irq_map) 166 167 int process_portal_irq_map(int ifd, struct dpaa_ioctl_irq_map *map) 168 { 169 map->fd = fd; 170 return ioctl(ifd, DPAA_IOCTL_PORTAL_IRQ_MAP, map); 171 } 172 173 int process_portal_irq_unmap(int ifd) 174 { 175 return close(ifd); 176 } 177 178 struct dpaa_ioctl_raw_portal { 179 /* inputs */ 180 enum dpaa_portal_type type; /* Type of portal to allocate */ 181 182 uint8_t enable_stash; /* set to non zero to turn on stashing */ 183 /* Stashing attributes for the portal */ 184 uint32_t cpu; 185 uint32_t cache; 186 uint32_t window; 187 /* Specifies the stash request queue this portal should use */ 188 uint8_t sdest; 189 190 /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX 191 * for don't care. The portal index will be populated by the 192 * driver when the ioctl() successfully completes. 193 */ 194 uint32_t index; 195 196 /* outputs */ 197 uint64_t cinh; 198 uint64_t cena; 199 }; 200 201 #define DPAA_IOCTL_ALLOC_RAW_PORTAL \ 202 _IOWR(DPAA_IOCTL_MAGIC, 0x0C, struct dpaa_ioctl_raw_portal) 203 204 #define DPAA_IOCTL_FREE_RAW_PORTAL \ 205 _IOR(DPAA_IOCTL_MAGIC, 0x0D, struct dpaa_ioctl_raw_portal) 206 207 static int process_portal_allocate(struct dpaa_ioctl_raw_portal *portal) 208 { 209 int ret = check_fd(); 210 211 if (ret) 212 return ret; 213 214 ret = ioctl(fd, DPAA_IOCTL_ALLOC_RAW_PORTAL, portal); 215 if (ret) { 216 perror("ioctl(DPAA_IOCTL_ALLOC_RAW_PORTAL)"); 217 return ret; 218 } 219 return 0; 220 } 221 222 static int process_portal_free(struct dpaa_ioctl_raw_portal *portal) 223 { 224 int ret = check_fd(); 225 226 if (ret) 227 return ret; 228 229 ret = ioctl(fd, DPAA_IOCTL_FREE_RAW_PORTAL, portal); 230 if (ret) { 231 perror("ioctl(DPAA_IOCTL_FREE_RAW_PORTAL)"); 232 return ret; 233 } 234 return 0; 235 } 236 237 int qman_allocate_raw_portal(struct dpaa_raw_portal *portal) 238 { 239 struct dpaa_ioctl_raw_portal input; 240 int ret; 241 242 input.type = dpaa_portal_qman; 243 input.index = portal->index; 244 input.enable_stash = portal->enable_stash; 245 input.cpu = portal->cpu; 246 input.cache = portal->cache; 247 input.window = portal->window; 248 input.sdest = portal->sdest; 249 250 ret = process_portal_allocate(&input); 251 if (ret) 252 return ret; 253 portal->index = input.index; 254 portal->cinh = input.cinh; 255 portal->cena = input.cena; 256 return 0; 257 } 258 259 int qman_free_raw_portal(struct dpaa_raw_portal *portal) 260 { 261 struct dpaa_ioctl_raw_portal input; 262 263 input.type = dpaa_portal_qman; 264 input.index = portal->index; 265 input.cinh = portal->cinh; 266 input.cena = portal->cena; 267 268 return process_portal_free(&input); 269 } 270 271 int bman_allocate_raw_portal(struct dpaa_raw_portal *portal) 272 { 273 struct dpaa_ioctl_raw_portal input; 274 int ret; 275 276 input.type = dpaa_portal_bman; 277 input.index = portal->index; 278 input.enable_stash = 0; 279 280 ret = process_portal_allocate(&input); 281 if (ret) 282 return ret; 283 portal->index = input.index; 284 portal->cinh = input.cinh; 285 portal->cena = input.cena; 286 return 0; 287 } 288 289 int bman_free_raw_portal(struct dpaa_raw_portal *portal) 290 { 291 struct dpaa_ioctl_raw_portal input; 292 293 input.type = dpaa_portal_bman; 294 input.index = portal->index; 295 input.cinh = portal->cinh; 296 input.cena = portal->cena; 297 298 return process_portal_free(&input); 299 } 300 301 #define DPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT \ 302 _IOW(DPAA_IOCTL_MAGIC, 0x0E, struct usdpaa_ioctl_link_status) 303 304 #define DPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT \ 305 _IOW(DPAA_IOCTL_MAGIC, 0x0F, char*) 306 307 int dpaa_intr_enable(char *if_name, int efd) 308 { 309 struct usdpaa_ioctl_link_status args; 310 311 int ret = check_fd(); 312 313 if (ret) 314 return ret; 315 316 args.efd = (uint32_t)efd; 317 strcpy(args.if_name, if_name); 318 319 ret = ioctl(fd, DPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT, &args); 320 if (ret) 321 return errno; 322 323 return 0; 324 } 325 326 int dpaa_intr_disable(char *if_name) 327 { 328 int ret = check_fd(); 329 330 if (ret) 331 return ret; 332 333 ret = ioctl(fd, DPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT, &if_name); 334 if (ret) { 335 if (errno == EINVAL) 336 printf("Failed to disable interrupt: Not Supported\n"); 337 else 338 printf("Failed to disable interrupt\n"); 339 return ret; 340 } 341 342 return 0; 343 } 344 345 #define DPAA_IOCTL_GET_IOCTL_VERSION \ 346 _IOR(DPAA_IOCTL_MAGIC, 0x14, int) 347 348 int dpaa_get_ioctl_version_number(void) 349 { 350 int version_num, ret = check_fd(); 351 352 if (ret) 353 return ret; 354 355 ret = ioctl(fd, DPAA_IOCTL_GET_IOCTL_VERSION, &version_num); 356 if (ret) { 357 if (errno == EINVAL) { 358 version_num = 1; 359 } else { 360 printf("Failed to get ioctl version number\n"); 361 version_num = -1; 362 } 363 } 364 365 return version_num; 366 } 367 368 #define DPAA_IOCTL_GET_LINK_STATUS \ 369 _IOWR(DPAA_IOCTL_MAGIC, 0x10, struct usdpaa_ioctl_link_status_args) 370 371 #define DPAA_IOCTL_GET_LINK_STATUS_OLD \ 372 _IOWR(DPAA_IOCTL_MAGIC, 0x10, struct usdpaa_ioctl_link_status_args_old) 373 374 375 int dpaa_get_link_status(char *if_name, struct rte_eth_link *link) 376 { 377 int ioctl_version, ret = check_fd(); 378 379 if (ret) 380 return ret; 381 382 ioctl_version = dpaa_get_ioctl_version_number(); 383 384 if (ioctl_version == 2) { 385 struct usdpaa_ioctl_link_status_args args; 386 387 strcpy(args.if_name, if_name); 388 389 ret = ioctl(fd, DPAA_IOCTL_GET_LINK_STATUS, &args); 390 if (ret) { 391 printf("Failed to get link status\n"); 392 return ret; 393 } 394 395 link->link_status = args.link_status; 396 link->link_speed = args.link_speed; 397 link->link_duplex = args.link_duplex; 398 link->link_autoneg = args.link_autoneg; 399 } else { 400 struct usdpaa_ioctl_link_status_args_old args; 401 402 strcpy(args.if_name, if_name); 403 404 ret = ioctl(fd, DPAA_IOCTL_GET_LINK_STATUS_OLD, &args); 405 if (ret) { 406 if (errno == EINVAL) 407 printf("Get link status: Not Supported\n"); 408 else 409 printf("Failed to get link status\n"); 410 return ret; 411 } 412 413 link->link_status = args.link_status; 414 } 415 416 return 0; 417 } 418 419 #define DPAA_IOCTL_UPDATE_LINK_STATUS \ 420 _IOW(DPAA_IOCTL_MAGIC, 0x11, struct usdpaa_ioctl_update_link_status_args) 421 422 int dpaa_update_link_status(char *if_name, int link_status) 423 { 424 struct usdpaa_ioctl_update_link_status_args args; 425 int ret; 426 427 ret = check_fd(); 428 if (ret) 429 return ret; 430 431 strcpy(args.if_name, if_name); 432 args.link_status = link_status; 433 434 ret = ioctl(fd, DPAA_IOCTL_UPDATE_LINK_STATUS, &args); 435 if (ret) { 436 if (errno == EINVAL) 437 printf("Failed to set link status: Not Supported\n"); 438 else 439 printf("Failed to set link status"); 440 return ret; 441 } 442 443 return 0; 444 } 445 446 #define DPAA_IOCTL_UPDATE_LINK_SPEED \ 447 _IOW(DPAA_IOCTL_MAGIC, 0x12, struct usdpaa_ioctl_update_link_speed) 448 449 int dpaa_update_link_speed(char *if_name, int link_speed, int link_duplex) 450 { 451 struct usdpaa_ioctl_update_link_speed args; 452 int ret; 453 454 ret = check_fd(); 455 if (ret) 456 return ret; 457 458 strcpy(args.if_name, if_name); 459 args.link_speed = link_speed; 460 args.link_duplex = link_duplex; 461 462 ret = ioctl(fd, DPAA_IOCTL_UPDATE_LINK_SPEED, &args); 463 if (ret) { 464 if (errno == EINVAL) 465 printf("Failed to set link speed: Not Supported\n"); 466 else 467 printf("Failed to set link speed\n"); 468 return ret; 469 } 470 471 return ret; 472 } 473 474 #define DPAA_IOCTL_RESTART_LINK_AUTONEG \ 475 _IOW(DPAA_IOCTL_MAGIC, 0x13, char *) 476 477 int dpaa_restart_link_autoneg(char *if_name) 478 { 479 int ret = check_fd(); 480 481 if (ret) 482 return ret; 483 484 ret = ioctl(fd, DPAA_IOCTL_RESTART_LINK_AUTONEG, &if_name); 485 if (ret) { 486 if (errno == EINVAL) 487 printf("Failed to restart autoneg: Not Supported\n"); 488 else 489 printf("Failed to restart autoneg\n"); 490 return ret; 491 } 492 493 return ret; 494 } 495