1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2015-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 * SPDX-License-Identifier: MIT 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24 #include "conftest.h" 25 26 #include "nvlink_os.h" 27 #include "nvlink_linux.h" 28 #include "nvlink_errors.h" 29 #include "nvlink_export.h" 30 #include "nv-linux.h" 31 #include "nv-procfs.h" 32 #include "nv-time.h" 33 #include "nvlink_caps.h" 34 35 #include <linux/module.h> 36 #include <linux/major.h> 37 #include <linux/cdev.h> 38 #include <linux/device.h> 39 #include <linux/string.h> 40 #include <linux/mutex.h> 41 42 #define MAX_ERROR_STRING 512 43 44 typedef struct nvlink_file_private 45 { 46 struct 47 { 48 /* A duped file descriptor for fabric_mgmt capability */ 49 int fabric_mgmt; 50 } capability_fds; 51 } nvlink_file_private_t; 52 53 #define NVLINK_SET_FILE_PRIVATE(filp, data) ((filp)->private_data = (data)) 54 #define NVLINK_GET_FILE_PRIVATE(filp) ((nvlink_file_private_t *)(filp)->private_data) 55 56 typedef struct 57 { 58 struct mutex lock; 59 NvBool initialized; 60 struct cdev cdev; 61 dev_t devno; 62 int opened; 63 int major_devnum; 64 } _nvlink_drvctx; 65 66 67 // nvlink driver local state 68 static _nvlink_drvctx nvlink_drvctx; 69 70 #if defined(CONFIG_PROC_FS) 71 #define NV_DEFINE_SINGLE_NVLINK_PROCFS_FILE(name) \ 72 NV_DEFINE_SINGLE_PROCFS_FILE_READ_ONLY(name, nv_system_pm_lock) 73 #endif 74 75 #define NVLINK_PROCFS_DIR "driver/nvidia-nvlink" 76 77 static struct proc_dir_entry *nvlink_procfs_dir = NULL; 78 79 #if defined(CONFIG_PROC_FS) 80 static int nvlink_is_procfs_available = 1; 81 #else 82 static int nvlink_is_procfs_available = 0; 83 #endif 84 85 static struct proc_dir_entry *nvlink_permissions = NULL; 86 87 static int nv_procfs_read_permissions(struct seq_file *s, void *v) 88 { 89 // Restrict device node permissions - 0666. 90 seq_printf(s, "%s: %u\n", "DeviceFileMode", 438); 91 92 return 0; 93 } 94 95 NV_DEFINE_SINGLE_NVLINK_PROCFS_FILE(permissions); 96 97 static void nvlink_permissions_exit(void) 98 { 99 if (!nvlink_permissions) 100 { 101 return; 102 } 103 104 proc_remove(nvlink_permissions); 105 nvlink_permissions = NULL; 106 } 107 108 static int nvlink_permissions_init(void) 109 { 110 if (!nvlink_procfs_dir) 111 { 112 return -EACCES; 113 } 114 115 nvlink_permissions = NV_CREATE_PROC_FILE("permissions", 116 nvlink_procfs_dir, 117 permissions, 118 NULL); 119 if (!nvlink_permissions) 120 { 121 return -EACCES; 122 } 123 124 return 0; 125 } 126 127 static void nvlink_procfs_exit(void) 128 { 129 nvlink_permissions_exit(); 130 131 if (!nvlink_procfs_dir) 132 { 133 return; 134 } 135 136 proc_remove(nvlink_procfs_dir); 137 nvlink_procfs_dir = NULL; 138 } 139 140 static int nvlink_procfs_init(void) 141 { 142 int rc = 0; 143 144 if (!nvlink_is_procfs_available) 145 { 146 return -EACCES; 147 } 148 149 nvlink_procfs_dir = NV_CREATE_PROC_DIR(NVLINK_PROCFS_DIR, NULL); 150 if (!nvlink_procfs_dir) 151 { 152 return -EACCES; 153 } 154 155 rc = nvlink_permissions_init(); 156 if (rc < 0) 157 { 158 goto cleanup; 159 } 160 161 return 0; 162 163 cleanup: 164 165 nvlink_procfs_exit(); 166 167 return rc; 168 } 169 170 static int nvlink_fops_open(struct inode *inode, struct file *filp) 171 { 172 int rc = 0; 173 nvlink_file_private_t *private = NULL; 174 175 nvlink_print(NVLINK_DBG_INFO, "nvlink driver open\n"); 176 177 mutex_lock(&nvlink_drvctx.lock); 178 179 // nvlink lib driver is currently exclusive open. 180 if (nvlink_drvctx.opened) 181 { 182 rc = -EBUSY; 183 goto open_error; 184 } 185 186 private = (nvlink_file_private_t *)nvlink_malloc(sizeof(*private)); 187 if (private == NULL) 188 { 189 rc = -ENOMEM; 190 goto open_error; 191 } 192 193 private->capability_fds.fabric_mgmt = -1; 194 NVLINK_SET_FILE_PRIVATE(filp, private); 195 196 // mark our state as opened 197 nvlink_drvctx.opened = NV_TRUE; 198 199 open_error: 200 mutex_unlock(&nvlink_drvctx.lock); 201 return rc; 202 } 203 204 static int nvlink_fops_release(struct inode *inode, struct file *filp) 205 { 206 nvlink_file_private_t *private = NVLINK_GET_FILE_PRIVATE(filp); 207 208 nvlink_print(NVLINK_DBG_INFO, "nvlink driver close\n"); 209 210 if (private == NULL) 211 return -ENOMEM; 212 213 mutex_lock(&nvlink_drvctx.lock); 214 215 if (private->capability_fds.fabric_mgmt > 0) 216 { 217 nvlink_cap_release(private->capability_fds.fabric_mgmt); 218 private->capability_fds.fabric_mgmt = -1; 219 } 220 221 nvlink_free(filp->private_data); 222 NVLINK_SET_FILE_PRIVATE(filp, NULL); 223 224 // mark the device as not opened 225 nvlink_drvctx.opened = NV_FALSE; 226 227 mutex_unlock(&nvlink_drvctx.lock); 228 229 return 0; 230 } 231 232 static int nvlink_fops_ioctl(struct inode *inode, 233 struct file *filp, 234 unsigned int cmd, 235 unsigned long arg) 236 { 237 nvlink_ioctrl_params ctrl_params = {0}; 238 int param_size = _IOC_SIZE(cmd); 239 void *param_buf = NULL; 240 NvlStatus ret_val = 0; 241 int rc = 0; 242 243 // no buffer for simple _IO types 244 if (param_size) 245 { 246 // allocate a buffer to hold user input 247 param_buf = kzalloc(param_size, GFP_KERNEL); 248 if (NULL == param_buf) 249 { 250 rc = -ENOMEM; 251 goto nvlink_ioctl_fail; 252 } 253 254 // copy user input to kernel buffers. Simple _IOR() ioctls can skip this step. 255 if (_IOC_DIR(cmd) & _IOC_WRITE) 256 { 257 // copy user input to local buffer 258 if (copy_from_user(param_buf, (const void *)arg, param_size)) 259 { 260 rc = -EFAULT; 261 goto nvlink_ioctl_fail; 262 } 263 } 264 } 265 266 ctrl_params.osPrivate = filp->private_data; 267 ctrl_params.cmd = _IOC_NR(cmd); 268 ctrl_params.buf = param_buf; 269 ctrl_params.size = param_size; 270 271 ret_val = nvlink_lib_ioctl_ctrl(&ctrl_params); 272 if (NVL_SUCCESS != ret_val) 273 { 274 rc = -EINVAL; 275 goto nvlink_ioctl_fail; 276 } 277 278 // no copy for write-only ioctl 279 if ((param_size) && (_IOC_DIR(cmd) & _IOC_READ)) 280 { 281 if (copy_to_user((void *)arg, ctrl_params.buf, ctrl_params.size)) 282 { 283 rc = -EFAULT; 284 goto nvlink_ioctl_fail; 285 } 286 } 287 288 nvlink_ioctl_fail: 289 if (param_buf) 290 { 291 kfree(param_buf); 292 } 293 return rc; 294 } 295 296 #define NV_FILE_INODE(file) (file)->f_inode 297 298 static long nvlink_fops_unlocked_ioctl(struct file *file, 299 unsigned int cmd, 300 unsigned long arg) 301 { 302 return nvlink_fops_ioctl(NV_FILE_INODE(file), file, cmd, arg); 303 } 304 305 306 static const struct file_operations nvlink_fops = { 307 .owner = THIS_MODULE, 308 .open = nvlink_fops_open, 309 .release = nvlink_fops_release, 310 .unlocked_ioctl = nvlink_fops_unlocked_ioctl, 311 }; 312 313 int __init nvlink_core_init(void) 314 { 315 NvlStatus ret_val; 316 int rc; 317 318 if (NV_TRUE == nvlink_drvctx.initialized) 319 { 320 nvlink_print(NVLINK_DBG_ERRORS, "nvlink core interface already initialized\n"); 321 return -EBUSY; 322 } 323 324 mutex_init(&nvlink_drvctx.lock); 325 326 ret_val = nvlink_lib_initialize(); 327 if (NVL_SUCCESS != ret_val) 328 { 329 nvlink_print(NVLINK_DBG_ERRORS, "Failed to initialize driver : %d\n", ret_val); 330 rc = -ENODEV; 331 goto nvlink_lib_initialize_fail; 332 } 333 334 rc = alloc_chrdev_region(&nvlink_drvctx.devno, 0, NVLINK_NUM_MINOR_DEVICES, 335 NVLINK_DEVICE_NAME); 336 if (rc < 0) 337 { 338 nvlink_print(NVLINK_DBG_ERRORS, "alloc_chrdev_region failed: %d\n", rc); 339 goto alloc_chrdev_region_fail; 340 } 341 342 nvlink_drvctx.major_devnum = MAJOR(nvlink_drvctx.devno); 343 nvlink_print(NVLINK_DBG_INFO, "Nvlink Core is being initialized, major device number %d\n", 344 nvlink_drvctx.major_devnum); 345 346 cdev_init(&nvlink_drvctx.cdev, &nvlink_fops); 347 nvlink_drvctx.cdev.owner = THIS_MODULE; 348 rc = cdev_add(&nvlink_drvctx.cdev, nvlink_drvctx.devno, NVLINK_NUM_MINOR_DEVICES); 349 if (rc < 0) 350 { 351 nvlink_print(NVLINK_DBG_ERRORS, " Unable to create cdev\n"); 352 goto cdev_add_fail; 353 } 354 355 rc = nvlink_procfs_init(); 356 if (rc < 0) 357 { 358 goto procfs_init_fail; 359 } 360 361 rc = nvlink_cap_init(NVLINK_PROCFS_DIR); 362 if (rc < 0) 363 { 364 nvlink_print(NVLINK_DBG_ERRORS, " Unable to create capability\n"); 365 goto cap_init_fail; 366 } 367 368 nvlink_drvctx.initialized = NV_TRUE; 369 370 return 0; 371 372 cap_init_fail: 373 nvlink_procfs_exit(); 374 375 procfs_init_fail: 376 cdev_del(&nvlink_drvctx.cdev); 377 378 cdev_add_fail: 379 unregister_chrdev_region(nvlink_drvctx.devno, NVLINK_NUM_MINOR_DEVICES); 380 381 alloc_chrdev_region_fail: 382 nvlink_lib_unload(); 383 384 nvlink_lib_initialize_fail: 385 nv_mutex_destroy(&nvlink_drvctx.lock); 386 return rc; 387 } 388 389 void nvlink_core_exit(void) 390 { 391 if (NV_FALSE == nvlink_drvctx.initialized) 392 { 393 return; 394 } 395 396 nvlink_cap_exit(); 397 398 nvlink_procfs_exit(); 399 400 cdev_del(&nvlink_drvctx.cdev); 401 402 unregister_chrdev_region(nvlink_drvctx.devno, NVLINK_NUM_MINOR_DEVICES); 403 404 nvlink_lib_unload(); 405 406 nv_mutex_destroy(&nvlink_drvctx.lock); 407 408 nvlink_print(NVLINK_DBG_INFO, "Unregistered Nvlink Core, major device number %d\n", 409 nvlink_drvctx.major_devnum); 410 } 411 412 void 413 nvlink_print 414 ( 415 const char *file, 416 int line, 417 const char *function, 418 int log_level, 419 const char *fmt, 420 ... 421 ) 422 { 423 va_list arglist; 424 char nv_string[MAX_ERROR_STRING]; 425 char *sys_log_level; 426 427 switch (log_level) { 428 case NVLINK_DBG_LEVEL_INFO: 429 sys_log_level = KERN_INFO; 430 break; 431 case NVLINK_DBG_LEVEL_SETUP: 432 sys_log_level = KERN_DEBUG; 433 break; 434 case NVLINK_DBG_LEVEL_USERERRORS: 435 sys_log_level = KERN_NOTICE; 436 break; 437 case NVLINK_DBG_LEVEL_WARNINGS: 438 sys_log_level = KERN_WARNING; 439 break; 440 case NVLINK_DBG_LEVEL_ERRORS: 441 sys_log_level = KERN_ERR; 442 break; 443 default: 444 sys_log_level = KERN_INFO; 445 break; 446 } 447 448 va_start(arglist, fmt); 449 vsnprintf(nv_string, sizeof(nv_string), fmt, arglist); 450 va_end(arglist); 451 452 nv_string[sizeof(nv_string) - 1] = '\0'; 453 printk("%snvidia-nvlink: %s", sys_log_level, nv_string); 454 } 455 456 void * nvlink_malloc(NvLength size) 457 { 458 return kmalloc(size, GFP_KERNEL); 459 } 460 461 void nvlink_free(void *ptr) 462 { 463 return kfree(ptr); 464 } 465 466 char * nvlink_strcpy(char *dest, const char *src) 467 { 468 return strcpy(dest, src); 469 } 470 471 int nvlink_strcmp(const char *dest, const char *src) 472 { 473 return strcmp(dest, src); 474 } 475 476 NvLength nvlink_strlen(const char *s) 477 { 478 return strlen(s); 479 } 480 481 int nvlink_snprintf(char *dest, NvLength size, const char *fmt, ...) 482 { 483 va_list arglist; 484 int chars_written; 485 486 va_start(arglist, fmt); 487 chars_written = vsnprintf(dest, size, fmt, arglist); 488 va_end(arglist); 489 490 return chars_written; 491 } 492 493 NvU32 nvlink_memRd32(const volatile void * address) 494 { 495 return (*(const volatile NvU32*)(address)); 496 } 497 498 void nvlink_memWr32(volatile void *address, NvU32 data) 499 { 500 (*(volatile NvU32 *)(address)) = data; 501 } 502 503 NvU64 nvlink_memRd64(const volatile void * address) 504 { 505 return (*(const volatile NvU64 *)(address)); 506 } 507 508 void nvlink_memWr64(volatile void *address, NvU64 data) 509 { 510 (*(volatile NvU64 *)(address)) = data; 511 } 512 513 void * nvlink_memset(void *dest, int value, NvLength size) 514 { 515 return memset(dest, value, size); 516 } 517 518 void * nvlink_memcpy(void *dest, const void *src, NvLength size) 519 { 520 return memcpy(dest, src, size); 521 } 522 523 int nvlink_memcmp(const void *s1, const void *s2, NvLength size) 524 { 525 return memcmp(s1, s2, size); 526 } 527 528 /* 529 * Sleep for specified milliseconds. Yields the CPU to scheduler. 530 */ 531 void nvlink_sleep(unsigned int ms) 532 { 533 NV_STATUS status; 534 535 status = nv_sleep_ms(ms); 536 537 if (status != NV_OK) 538 { 539 if (printk_ratelimit()) 540 { 541 nvlink_print(NVLINK_DBG_ERRORS, "NVLink: requested sleep duration" 542 " %d msec exceeded %d msec\n", 543 ms, NV_MAX_ISR_DELAY_MS); 544 WARN_ON(1); 545 } 546 } 547 } 548 549 void nvlink_assert(int cond) 550 { 551 if ((cond) == 0x0) 552 { 553 if (printk_ratelimit()) 554 { 555 nvlink_print(NVLINK_DBG_ERRORS, "NVLink: Assertion failed!\n"); 556 WARN_ON(1); 557 } 558 559 dbg_breakpoint(); 560 } 561 } 562 563 void * nvlink_allocLock(void) 564 { 565 struct semaphore *sema; 566 567 sema = nvlink_malloc(sizeof(*sema)); 568 if (sema == NULL) 569 { 570 nvlink_print(NVLINK_DBG_ERRORS, "Failed to allocate sema!\n"); 571 return NULL; 572 } 573 sema_init(sema, 1); 574 575 return sema; 576 } 577 578 void nvlink_acquireLock(void *hLock) 579 { 580 down(hLock); 581 } 582 583 void nvlink_releaseLock(void *hLock) 584 { 585 up(hLock); 586 } 587 588 void nvlink_freeLock(void *hLock) 589 { 590 if (NULL == hLock) 591 { 592 return; 593 } 594 595 NVLINK_FREE(hLock); 596 } 597 598 NvBool nvlink_isLockOwner(void *hLock) 599 { 600 return NV_TRUE; 601 } 602 603 NvlStatus nvlink_acquire_fabric_mgmt_cap(void *osPrivate, NvU64 capDescriptor) 604 { 605 int dup_fd = -1; 606 nvlink_file_private_t *private_data = (nvlink_file_private_t *)osPrivate; 607 608 if (private_data == NULL) 609 { 610 return NVL_BAD_ARGS; 611 } 612 613 dup_fd = nvlink_cap_acquire((int)capDescriptor, 614 NVLINK_CAP_FABRIC_MANAGEMENT); 615 if (dup_fd < 0) 616 { 617 return NVL_ERR_OPERATING_SYSTEM; 618 } 619 620 private_data->capability_fds.fabric_mgmt = dup_fd; 621 return NVL_SUCCESS; 622 } 623 624 int nvlink_is_fabric_manager(void *osPrivate) 625 { 626 nvlink_file_private_t *private_data = (nvlink_file_private_t *)osPrivate; 627 628 /* Make sure that fabric mgmt capbaility fd is valid */ 629 if ((private_data == NULL) || 630 (private_data->capability_fds.fabric_mgmt < 0)) 631 { 632 return 0; 633 } 634 635 return 1; 636 } 637 638 int nvlink_is_admin(void) 639 { 640 return NV_IS_SUSER(); 641 } 642