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