1 /******************************************************************************* 2 Copyright (c) 2019-2023 NVidia Corporation 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to 6 deal in the Software without restriction, including without limitation the 7 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 sell copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be 12 included in all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 DEALINGS IN THE SOFTWARE. 21 *******************************************************************************/ 22 23 #include "nvlink.h" 24 #include "nvlink_export.h" 25 #include "nvlink_os.h" 26 #include "nvlink_ctx.h" 27 #include "nvlink_helper.h" 28 29 #include "nvlink_lock.h" 30 31 nvlink_lib_context nvlinkLibCtx = {0}; 32 33 /* 34 * Initialize the nvlink core library 35 * 36 * return NVL_SUCCESS if the library is initialized successfully 37 */ 38 NvlStatus 39 nvlink_lib_initialize(void) 40 { 41 NvlStatus lock_status = NVL_SUCCESS; 42 43 if (nvlinkLibCtx.nv_devicelist_head.initialized == 0) 44 { 45 // Allocate top-level lock 46 lock_status = nvlink_lib_top_lock_alloc(); 47 if (lock_status != NVL_SUCCESS) 48 { 49 NVLINK_PRINT((DBG_MODULE_NVLINK_CORE, NVLINK_DBG_LEVEL_ERRORS, 50 "%s: Failed to allocate top-level lock\n", 51 __FUNCTION__)); 52 53 return lock_status; 54 } 55 56 // Acquire top-level lock 57 lock_status = nvlink_lib_top_lock_acquire(); 58 if (lock_status != NVL_SUCCESS) 59 { 60 NVLINK_PRINT((DBG_MODULE_NVLINK_CORE, NVLINK_DBG_LEVEL_ERRORS, 61 "%s: Failed to acquire top-level lock\n", 62 __FUNCTION__)); 63 64 return lock_status; 65 } 66 67 // Top-level lock is now acquired 68 69 // Initialize the device list head 70 nvListInit(&nvlinkLibCtx.nv_devicelist_head.link_list); 71 nvListInit(&nvlinkLibCtx.nv_devicelist_head.node); 72 nvlinkLibCtx.nv_devicelist_head.initialized = 1; 73 74 // Initialize the intranode connection list head 75 nvListInit(&nvlinkLibCtx.nv_intraconn_head.node); 76 77 // Initialize the internode connection list head 78 nvListInit(&nvlinkLibCtx.nv_interconn_head.node); 79 80 // Initialize registered and connected links to 0 81 nvlinkLibCtx.registeredEndpoints = 0; 82 nvlinkLibCtx.connectedEndpoints = 0; 83 nvlinkLibCtx.notConnectedEndpoints = 0; 84 85 // 86 // Initialize fabric node id to max value until set 87 // by ioctl interface 88 // 89 nvlinkLibCtx.nodeId = NV_U16_MAX ; 90 91 // Release top-level lock 92 nvlink_lib_top_lock_release(); 93 } 94 95 return NVL_SUCCESS; 96 } 97 98 /* 99 * Unload the nvlink core library 100 * 101 * return NVL_SUCCESS if the library is unloaded successfully 102 */ 103 NvlStatus 104 nvlink_lib_unload(void) 105 { 106 NvlStatus lock_status = NVL_SUCCESS; 107 108 if (nvlink_lib_is_initialized()) 109 { 110 // Acquire top-level lock 111 lock_status = nvlink_lib_top_lock_acquire(); 112 if (lock_status != NVL_SUCCESS) 113 { 114 NVLINK_PRINT((DBG_MODULE_NVLINK_CORE, NVLINK_DBG_LEVEL_ERRORS, 115 "%s: Failed to acquire top-level lock\n", 116 __FUNCTION__)); 117 118 return lock_status; 119 } 120 121 // Top-level lock is now acquired 122 123 // Check if there are no devices registered 124 if (nvlink_lib_is_device_list_empty()) 125 { 126 nvlinkLibCtx.nv_devicelist_head.initialized = 0; 127 } 128 129 // Release and free top-level lock 130 nvlink_lib_top_lock_release(); 131 nvlink_lib_top_lock_free(); 132 } 133 134 return NVL_SUCCESS; 135 } 136 137 /* 138 * Check if the nvlink core library is initialized 139 * 140 * return NV_TRUE if the core library is already initialized 141 */ 142 NvBool 143 nvlink_lib_is_initialized(void) 144 { 145 return nvlinkLibCtx.nv_devicelist_head.initialized; 146 } 147 148 /* 149 * Check if there are any devices registered 150 * 151 * return NV_TRUE if there are devices registered in the core library 152 */ 153 NvBool 154 nvlink_lib_is_device_list_empty(void) 155 { 156 NvBool isEmpty = NV_TRUE; 157 158 isEmpty = nvListIsEmpty(&nvlinkLibCtx.nv_devicelist_head.node); 159 160 return isEmpty; 161 } 162 163 /* 164 * Get if a device registerd to the nvlink corelib has a reduced nvlink config 165 * 166 * return NV_TRUE if there is a device registered to the core library that is a reduced 167 * nvlink config device 168 */ 169 NvBool 170 nvlink_lib_is_registerd_device_with_reduced_config(void) 171 { 172 NvlStatus lock_status = NVL_SUCCESS; 173 nvlink_device *dev = NULL; 174 175 // Acquire top-level lock 176 lock_status = nvlink_lib_top_lock_acquire(); 177 if (lock_status != NVL_SUCCESS) 178 { 179 NVLINK_PRINT((DBG_MODULE_NVLINK_CORE, NVLINK_DBG_LEVEL_ERRORS, 180 "%s: Failed to acquire top-level lock\n", 181 __FUNCTION__)); 182 183 return NV_FALSE; 184 } 185 186 FOR_EACH_DEVICE_REGISTERED(dev, nvlinkLibCtx.nv_devicelist_head, node) 187 { 188 if (dev->bReducedNvlinkConfig == NV_TRUE) 189 { 190 return NV_TRUE; 191 } 192 } 193 194 // Release and free top-level lock 195 nvlink_lib_top_lock_release(); 196 nvlink_lib_top_lock_free(); 197 198 return NV_FALSE; 199 } 200 201 /* 202 * Get the number of devices that have the device type deviceType 203 */ 204 NvlStatus 205 nvlink_lib_return_device_count_by_type 206 ( 207 NvU32 deviceType, 208 NvU32 *numDevices 209 ) 210 { 211 NvlStatus lock_status = NVL_SUCCESS; 212 nvlink_device *dev = NULL; 213 NvU32 device_count = 0; 214 215 if (nvlink_lib_is_initialized()) 216 { 217 // Acquire top-level lock 218 lock_status = nvlink_lib_top_lock_acquire(); 219 if (lock_status != NVL_SUCCESS) 220 { 221 NVLINK_PRINT((DBG_MODULE_NVLINK_CORE, NVLINK_DBG_LEVEL_ERRORS, 222 "%s: Failed to acquire top-level lock\n", 223 __FUNCTION__)); 224 225 return lock_status; 226 } 227 228 // Top-level lock is now acquired 229 230 // Loop through device list 231 FOR_EACH_DEVICE_REGISTERED(dev, nvlinkLibCtx.nv_devicelist_head, node) 232 { 233 if (dev->type == deviceType) 234 { 235 device_count++; 236 } 237 } 238 239 // Release top-level lock 240 nvlink_lib_top_lock_release(); 241 } 242 *numDevices = device_count; 243 return NVL_SUCCESS; 244 } 245