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