// SPDX-License-Identifier: MIT
/*
 * Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "amdsmi_go_shim.h"

#include <amd_smi/amdsmi.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define nullptr ((void*)0)

#define MAX_SOCKET_ACROSS_SYSTEM 4
#define CPU_0 0
#define GPU_SENSOR_0 0
#define MAX_CPU_PER_SOCKET 4
#define MAX_PHYSICALCORE_ACROSS_SYSTEM 384
#define MAX_LOGICALCORE_ACROSS_SYSTEM 768
#define MAX_GPU_DEVICE_ACROSS_SYSTEM 24
#define MAX_GPU_POWER_FROM_DRIVER 0xFFFF

#define AMDSMI_DRIVER_NAME "AMDSMI"
#define AMDSMI_LIB_FILE "/opt/rocm/lib/libamd_smi.so"
#define AMDSMI_LIB64_FILE "/opt/rocm/lib64/libamd_smi.so"

#define AMDGPU_DRIVER_NAME "AMDGPUDriver"
#define AMDGPU_INITSTATE_FILE "/sys/module/amdgpu/initstate"

#define AMDHSMP_DRIVER_NAME "AMDHSMPDriver"
#define AMDHSMP_INITSTATE_FILE "/dev/hsmp"

static uint32_t num_apuSockets = GOAMDSMI_VALUE_0;
static uint32_t num_cpuSockets = GOAMDSMI_VALUE_0;
static uint32_t num_gpuSockets = GOAMDSMI_VALUE_0;
static uint32_t cpuInitCompleted = false;
static uint32_t gpuInitCompleted = false;
static uint32_t apuInitCompleted = false;

static uint32_t num_cpu_inAllSocket = GOAMDSMI_VALUE_0;
static uint32_t num_cpu_physicalCore_inAllSocket = GOAMDSMI_VALUE_0;
static uint32_t num_gpu_devices_inAllSocket = GOAMDSMI_VALUE_0;

static amdsmi_socket_handle amdsmi_apusocket_handle_all_socket[MAX_SOCKET_ACROSS_SYSTEM +
                                                               MAX_GPU_DEVICE_ACROSS_SYSTEM] = {0};
static amdsmi_socket_handle amdsmi_cpusocket_handle_all_socket[MAX_SOCKET_ACROSS_SYSTEM] = {0};
static amdsmi_socket_handle amdsmi_gpusocket_handle_all_socket[MAX_GPU_DEVICE_ACROSS_SYSTEM] = {0};
static amdsmi_processor_handle
    amdsmi_processor_handle_all_cpu_across_socket[MAX_SOCKET_ACROSS_SYSTEM * MAX_CPU_PER_SOCKET] = {
        0};
static amdsmi_processor_handle
    amdsmi_processor_handle_all_cpu_physicalCore_across_socket[MAX_PHYSICALCORE_ACROSS_SYSTEM] = {
        0};
static amdsmi_processor_handle
    amdsmi_processor_handle_all_gpu_device_across_socket[MAX_GPU_DEVICE_ACROSS_SYSTEM] = {0};

goamdsmi_status_t is_file_present(const char* driver_name, const char* file_name) {
  if (0 == access(file_name, F_OK)) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Success, %s found \"%s\" and returns:%d\n", driver_name, file_name,
             GOAMDSMI_STATUS_SUCCESS);
    }
    return GOAMDSMI_STATUS_SUCCESS;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
    printf("AMDSMI, Status, %s not found, missing \"%s\" and returns:%d\n", driver_name, file_name,
           GOAMDSMI_STATUS_FAILURE);
  }
  return GOAMDSMI_STATUS_FAILURE;
}

goamdsmi_status_t check_amdgpu_driver() {
  return is_file_present(AMDGPU_DRIVER_NAME, AMDGPU_INITSTATE_FILE);
}

goamdsmi_status_t check_hsmp_driver() {
  return is_file_present(AMDHSMP_DRIVER_NAME, AMDHSMP_INITSTATE_FILE);
}

goamdsmi_status_t go_shim_amdsmiapu_init(goamdsmi_Init_t goamdsmi_Init) {
  if ((GOAMDSMI_CPU_INIT == goamdsmi_Init) && (true == cpuInitCompleted)) {
    if ((GOAMDSMI_VALUE_0 == num_cpuSockets) || (GOAMDSMI_VALUE_0 == num_cpu_inAllSocket) ||
        (GOAMDSMI_VALUE_0 == num_cpu_physicalCore_inAllSocket)) {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
        printf(
            "AMDSMI, Failed, Returns previous enumurated AMDSMICPUInit:%d, CpuSocketCount:%d, "
            "CpuCount:%d, CpuPhysicalCoreCount:%d\n",
            GOAMDSMI_STATUS_FAILURE, num_cpuSockets, num_cpu_inAllSocket,
            num_cpu_physicalCore_inAllSocket);
      }
      return GOAMDSMI_STATUS_FAILURE;
    } else {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
        printf(
            "AMDSMI, Success, Returns previous enumurated AMDSMICPUInit:%d, CpuSocketCount:%d, "
            "CpuCount:%d, CpuPhysicalCoreCount:%d\n",
            GOAMDSMI_STATUS_SUCCESS, num_cpuSockets, num_cpu_inAllSocket,
            num_cpu_physicalCore_inAllSocket);
      }
      return GOAMDSMI_STATUS_SUCCESS;
    }
  }

  if ((GOAMDSMI_GPU_INIT == goamdsmi_Init) && (true == gpuInitCompleted)) {
    if ((GOAMDSMI_VALUE_0 == num_gpuSockets) || (GOAMDSMI_VALUE_0 == num_gpu_devices_inAllSocket)) {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
        printf(
            "AMDSMI, Failed, Returns previous enumurated AMDSMIGPUInit:%d, GpuSocketCount:%d, "
            "GpuCount:%d\n",
            GOAMDSMI_STATUS_FAILURE, num_gpuSockets, num_gpu_devices_inAllSocket);
      }
      return GOAMDSMI_STATUS_FAILURE;
    } else {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
        printf(
            "AMDSMI, Success, Returns previous enumurated AMDSMIGPUInit:%d, GpuSocketCount:%d, "
            "GpuCount:%d\n",
            GOAMDSMI_STATUS_SUCCESS, num_gpuSockets, num_gpu_devices_inAllSocket);
      }
      return GOAMDSMI_STATUS_SUCCESS;
    }
  }

  if ((GOAMDSMI_STATUS_SUCCESS == check_amdgpu_driver()) &&
      (GOAMDSMI_STATUS_SUCCESS == check_hsmp_driver())) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
      printf("AMDSMI, Status, Identified APU machine and going to enumurate APU\n");
    }

    if ((AMDSMI_STATUS_SUCCESS == amdsmi_init(AMDSMI_INIT_AMD_GPUS | AMDSMI_INIT_AMD_CPUS)) &&
        (AMDSMI_STATUS_SUCCESS == amdsmi_get_socket_handles(&num_apuSockets, nullptr)) &&
        (AMDSMI_STATUS_SUCCESS ==
         amdsmi_get_socket_handles(&num_apuSockets, &amdsmi_apusocket_handle_all_socket[0])) &&
        (GOAMDSMI_VALUE_0 != num_apuSockets)) {
      cpuInitCompleted = true;
      gpuInitCompleted = true;
      apuInitCompleted = true;
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
        printf("AMDSMI, Success, Identified APU machine ApuNumSockets=%d\n", num_apuSockets);
      }
      for (uint32_t socket_counter = 0; socket_counter < num_apuSockets; socket_counter++) {
        uint32_t num_cpu = GOAMDSMI_VALUE_0;
        uint32_t num_cpu_physicalCores = GOAMDSMI_VALUE_0;
        uint32_t num_gpu_devices = GOAMDSMI_VALUE_0;

        // CPU
        amdsmi_processor_type_t cpu_processor_type = AMDSMI_PROCESSOR_TYPE_AMD_CPU;
        amdsmi_processor_type_t cpu_core_processor_type = AMDSMI_PROCESSOR_TYPE_AMD_CPU_CORE;
        if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_processor_handles_by_type(
                                          amdsmi_apusocket_handle_all_socket[socket_counter],
                                          cpu_processor_type, nullptr, &num_cpu)) &&
            (GOAMDSMI_VALUE_0 != num_cpu) &&
            (AMDSMI_STATUS_SUCCESS ==
             amdsmi_get_processor_handles_by_type(
                 amdsmi_apusocket_handle_all_socket[socket_counter], cpu_processor_type,
                 &amdsmi_processor_handle_all_cpu_across_socket[num_cpu_inAllSocket], &num_cpu))) {
          if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_processor_handles_by_type(
                                            amdsmi_apusocket_handle_all_socket[socket_counter],
                                            cpu_core_processor_type, nullptr,
                                            &num_cpu_physicalCores)) &&
              (GOAMDSMI_VALUE_0 != num_cpu_physicalCores) &&
              (AMDSMI_STATUS_SUCCESS ==
               amdsmi_get_processor_handles_by_type(
                   amdsmi_apusocket_handle_all_socket[socket_counter], cpu_core_processor_type,
                   &amdsmi_processor_handle_all_cpu_physicalCore_across_socket
                       [num_cpu_physicalCore_inAllSocket],
                   &num_cpu_physicalCores))) {
            num_cpu_physicalCore_inAllSocket =
                num_cpu_physicalCore_inAllSocket + num_cpu_physicalCores;
          }
          num_cpu_inAllSocket = num_cpu_inAllSocket + num_cpu;
          num_cpuSockets = num_cpuSockets + 1;
        }

        // GPU
        amdsmi_processor_type_t gpu_device_processor_type = AMDSMI_PROCESSOR_TYPE_AMD_GPU;
        if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_processor_handles_by_type(
                                          amdsmi_apusocket_handle_all_socket[socket_counter],
                                          gpu_device_processor_type, nullptr, &num_gpu_devices)) &&
            (GOAMDSMI_VALUE_0 != num_gpu_devices) &&
            (AMDSMI_STATUS_SUCCESS ==
             amdsmi_get_processor_handles_by_type(
                 amdsmi_apusocket_handle_all_socket[socket_counter], gpu_device_processor_type,
                 &amdsmi_processor_handle_all_gpu_device_across_socket[num_gpu_devices_inAllSocket],
                 &num_gpu_devices))) {
          num_gpu_devices_inAllSocket = num_gpu_devices_inAllSocket + num_gpu_devices;
          num_gpuSockets = num_gpuSockets + 1;
        }
      }
    }
  } else if (GOAMDSMI_CPU_INIT == goamdsmi_Init) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
      printf("AMDSMI, Status, Going to enumurate only CPU\n");
    }
    cpuInitCompleted = true;

    if (GOAMDSMI_STATUS_SUCCESS == check_hsmp_driver()) {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
        printf("AMDSMI, Status, Identified CPU Driver and going to enumurate only CPU\n");
      }

      if ((AMDSMI_STATUS_SUCCESS != amdsmi_init(AMDSMI_INIT_AMD_CPUS)) ||
          (AMDSMI_STATUS_SUCCESS != amdsmi_get_socket_handles(&num_cpuSockets, nullptr)) ||
          (AMDSMI_STATUS_SUCCESS !=
           amdsmi_get_socket_handles(&num_cpuSockets, &amdsmi_cpusocket_handle_all_socket[0])) ||
          (GOAMDSMI_VALUE_0 == num_cpuSockets)) {
        if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
          printf("AMDSMI, Failed, AMDSMICPUInit:0, CpuNumSockets=0\n");
        }
        return GOAMDSMI_STATUS_FAILURE;
      }
    } else {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_3)) {
        printf("AMDSMI, Status, Missing CPU Driver and not going to enumurate only CPU\n");
      }
    }
    // CPU
    for (uint32_t cpu_socket_counter = 0; cpu_socket_counter < num_cpuSockets;
         cpu_socket_counter++) {
      uint32_t num_cpu = GOAMDSMI_VALUE_0;
      uint32_t num_cpu_physicalCores = GOAMDSMI_VALUE_0;

      amdsmi_processor_type_t cpu_processor_type = AMDSMI_PROCESSOR_TYPE_AMD_CPU;
      amdsmi_processor_type_t cpu_core_processor_type = AMDSMI_PROCESSOR_TYPE_AMD_CPU_CORE;
      if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_processor_handles_by_type(
                                        amdsmi_cpusocket_handle_all_socket[cpu_socket_counter],
                                        cpu_processor_type, nullptr, &num_cpu)) &&
          (GOAMDSMI_VALUE_0 != num_cpu) &&
          (AMDSMI_STATUS_SUCCESS ==
           amdsmi_get_processor_handles_by_type(
               amdsmi_cpusocket_handle_all_socket[cpu_socket_counter], cpu_processor_type,
               &amdsmi_processor_handle_all_cpu_across_socket[num_cpu_inAllSocket], &num_cpu))) {
        if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_processor_handles_by_type(
                                          amdsmi_cpusocket_handle_all_socket[cpu_socket_counter],
                                          cpu_core_processor_type, nullptr,
                                          &num_cpu_physicalCores)) &&
            (GOAMDSMI_VALUE_0 != num_cpu_physicalCores) &&
            (AMDSMI_STATUS_SUCCESS ==
             amdsmi_get_processor_handles_by_type(
                 amdsmi_cpusocket_handle_all_socket[cpu_socket_counter], cpu_core_processor_type,
                 &amdsmi_processor_handle_all_cpu_physicalCore_across_socket
                     [num_cpu_physicalCore_inAllSocket],
                 &num_cpu_physicalCores))) {
          num_cpu_physicalCore_inAllSocket =
              num_cpu_physicalCore_inAllSocket + num_cpu_physicalCores;
        }
        num_cpu_inAllSocket = num_cpu_inAllSocket + num_cpu;
      }
    }
  } else if (GOAMDSMI_GPU_INIT == goamdsmi_Init) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
      printf("AMDSMI, Status, Going to enumurate only GPU\n");
    }
    gpuInitCompleted = true;

    if (GOAMDSMI_STATUS_SUCCESS == check_amdgpu_driver()) {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
        printf("AMDSMI, Status, Identified GPU Driver and going to enumurate only GPU\n");
      }

      if ((AMDSMI_STATUS_SUCCESS != amdsmi_init(AMDSMI_INIT_AMD_GPUS)) ||
          (AMDSMI_STATUS_SUCCESS != amdsmi_get_socket_handles(&num_gpuSockets, nullptr)) ||
          (AMDSMI_STATUS_SUCCESS !=
           amdsmi_get_socket_handles(&num_gpuSockets, &amdsmi_gpusocket_handle_all_socket[0])) ||
          (GOAMDSMI_VALUE_0 == num_gpuSockets)) {
        if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
          printf("AMDSMI, Failed, AMDSMIGPUInit:0, GpuNumSockets=0\n");
        }
        return GOAMDSMI_STATUS_FAILURE;
      }
    } else {
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_3)) {
        printf("AMDSMI, Status, Missing GPU Driver and not going to enumurate only GPU\n");
      }
    }

    // GPU
    for (uint32_t gpu_socket_counter = 0; gpu_socket_counter < num_gpuSockets;
         gpu_socket_counter++) {
      uint32_t num_gpu_devices = GOAMDSMI_VALUE_0;

      amdsmi_processor_type_t gpu_device_processor_type = AMDSMI_PROCESSOR_TYPE_AMD_GPU;
      if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_processor_handles_by_type(
                                        amdsmi_gpusocket_handle_all_socket[gpu_socket_counter],
                                        gpu_device_processor_type, nullptr, &num_gpu_devices)) &&
          (GOAMDSMI_VALUE_0 != num_gpu_devices) &&
          (AMDSMI_STATUS_SUCCESS ==
           amdsmi_get_processor_handles_by_type(
               amdsmi_gpusocket_handle_all_socket[gpu_socket_counter], gpu_device_processor_type,
               &amdsmi_processor_handle_all_gpu_device_across_socket[num_gpu_devices_inAllSocket],
               &num_gpu_devices))) {
        num_gpu_devices_inAllSocket = num_gpu_devices_inAllSocket + num_gpu_devices;
      }
    }
  }

  // CPU
  if ((GOAMDSMI_CPU_INIT == goamdsmi_Init) &&
      ((GOAMDSMI_VALUE_0 == num_cpuSockets) || (GOAMDSMI_VALUE_0 == num_cpu_inAllSocket) ||
       (GOAMDSMI_VALUE_0 == num_cpu_physicalCore_inAllSocket))) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf(
          "AMDSMI, Failed, CPU Enumuration Failed AMDSMICPUInit:%d, CpuSocketCount:%d, "
          "CpuCount:%d, CpuPhysicalCoreCount:%d,\n",
          GOAMDSMI_STATUS_FAILURE, num_cpuSockets, num_cpu_inAllSocket,
          num_cpu_physicalCore_inAllSocket);
    }
    return GOAMDSMI_STATUS_FAILURE;
  }

  // GPU
  if ((GOAMDSMI_GPU_INIT == goamdsmi_Init) &&
      ((GOAMDSMI_VALUE_0 == num_gpuSockets) || (GOAMDSMI_VALUE_0 == num_gpu_devices_inAllSocket))) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf(
          "AMDSMI, Failed, GPU Enumuration Failed AMDSMIGPUInit:%d, GpuSocketCount:%d, "
          "GpuCount:%d\n",
          GOAMDSMI_STATUS_FAILURE, num_gpuSockets, num_gpu_devices_inAllSocket);
    }
    return GOAMDSMI_STATUS_FAILURE;
  }

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    if ((GOAMDSMI_CPU_INIT == goamdsmi_Init) || apuInitCompleted)
      printf(
          "AMDSMI, Status, AMDSMICPUInit:%d, CpuSocketCount:%d, CpuCount:%d, "
          "CpuPhysicalCoreCount:%d,\n",
          GOAMDSMI_STATUS_SUCCESS, num_cpuSockets, num_cpu_inAllSocket,
          num_cpu_physicalCore_inAllSocket);
    if ((GOAMDSMI_GPU_INIT == goamdsmi_Init) || apuInitCompleted)
      printf("AMDSMI, Status, AMDSMIGPUInit:%d, GpuSocketCount:%d, GpuCount:%d\n",
             GOAMDSMI_STATUS_SUCCESS, num_gpuSockets, num_gpu_devices_inAllSocket);
  }

  return GOAMDSMI_STATUS_SUCCESS;
}
////////////////////////////////////////////////------------CPU------------////////////////////////////////////////////////
bool goamdsmi_cpu_init() {
  bool cpu_init_success = false;
  if (GOAMDSMI_STATUS_SUCCESS == go_shim_amdsmiapu_init(GOAMDSMI_CPU_INIT)) {
    if ((num_cpu_inAllSocket) && (num_cpu_physicalCore_inAllSocket)) cpu_init_success = true;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf(
        "AMDSMI, %s, InitAMDSMICPUInit:%d, CpuSocketCount:%d, CpuCount:%d, "
        "CpuPhysicalCoreCount:%d,\n",
        cpu_init_success ? "Success" : "Failed", cpu_init_success ? 1 : 0, num_cpuSockets,
        num_cpu_inAllSocket, num_cpu_physicalCore_inAllSocket);
  }
  return cpu_init_success;
}

uint32_t goamdsmi_cpu_threads_per_core_get() {
  bool readSuccess = false;
  uint32_t threads_per_core_temp = GOAMDSMI_VALUE_0;

#ifdef ENABLE_ESMI_LIB
  if ((AMDSMI_STATUS_SUCCESS == amdsmi_get_threads_per_core(&threads_per_core_temp)))
    readSuccess = true;
#endif
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s, CpuThreadsPerCore:%lu\n", readSuccess ? "Success" : "Failed",
           (unsigned long)(threads_per_core_temp));
  }

  return threads_per_core_temp;
}

uint32_t goamdsmi_cpu_number_of_threads_get() {
  bool readSuccess = false;
  uint32_t number_of_threads = GOAMDSMI_VALUE_0;
  uint32_t num_threads_per_core = goamdsmi_cpu_threads_per_core_get();
  if (0 != num_threads_per_core) {
    readSuccess = true;
    number_of_threads = num_cpu_physicalCore_inAllSocket * num_threads_per_core;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s, CpuNumThreads:%lu\n", readSuccess ? "Success" : "Failed",
           (unsigned long)(number_of_threads));
  }
  return number_of_threads;
}

uint32_t goamdsmi_cpu_number_of_sockets_get() {
  uint32_t number_of_sockets = num_cpuSockets;
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success, CpuNumSockets:%lu\n", (unsigned long)(number_of_sockets));
  }
  return number_of_sockets;
}

uint64_t goamdsmi_cpu_core_energy_get(uint32_t thread_index) {
  bool readSuccess = false;
  uint64_t core_energy_temp = GOAMDSMI_UINT64_MAX;
  uint32_t physicalCore_index = thread_index % num_cpu_physicalCore_inAllSocket;

#ifdef ENABLE_ESMI_LIB
  if (AMDSMI_STATUS_SUCCESS ==
      amdsmi_get_cpu_core_energy(
          amdsmi_processor_handle_all_cpu_physicalCore_across_socket[physicalCore_index],
          &core_energy_temp))
    readSuccess = true;
#endif
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf(
        "AMDSMI, %s for Thread:%d PC:%d, CpuCoreEnergy:%llu, CpuCoreEnergyJoules:%.6f, "
        "CpuCoreEnergyKJoules:%.9f\n",
        readSuccess ? "Success" : "Failed", thread_index, physicalCore_index,
        (unsigned long long)(core_energy_temp), ((double)(core_energy_temp)) / 1000000,
        ((double)(core_energy_temp)) / 1000000000);
  }

  return core_energy_temp;
}

uint64_t goamdsmi_cpu_socket_energy_get(uint32_t socket_index) {
  bool readSuccess = false;
  uint64_t socket_energy_temp = GOAMDSMI_UINT64_MAX;
#ifdef ENABLE_ESMI_LIB
  if ((AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_cpu_socket_energy(amdsmi_processor_handle_all_cpu_across_socket[socket_index],
                                    &socket_energy_temp)))
    readSuccess = true;
#else
  (void)socket_index;
#endif
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf(
        "AMDSMI, %s for Socket:%d, CpuSocketEnergy:%llu, CpuSocketEnergyJoules:%.6f, "
        "CpuSocketEnergyKJoules:%.9f\n",
        readSuccess ? "Success" : "Failed", socket_index, (unsigned long long)(socket_energy_temp),
        ((double)(socket_energy_temp)) / 1000000, ((double)(socket_energy_temp)) / 1000000000);
  }

  return socket_energy_temp;
}

uint32_t goamdsmi_cpu_prochot_status_get(uint32_t socket_index) {
  bool readSuccess = false;
  uint32_t prochot_temp = GOAMDSMI_UINT32_MAX;
#ifdef ENABLE_ESMI_LIB
  if ((AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_cpu_prochot_status(amdsmi_processor_handle_all_cpu_across_socket[socket_index],
                                     &prochot_temp)))
    readSuccess = true;
#else
  (void)socket_index;
#endif
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Socket:%d, CpuProchotStatus:%lu\n", readSuccess ? "Success" : "Failed",
           socket_index, (unsigned long)(prochot_temp));
  }

  return prochot_temp;
}

uint32_t goamdsmi_cpu_socket_power_get(uint32_t socket_index) {
  bool readSuccess = false;
  uint32_t socket_power_watts = 0;
  if ((AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_cpu_socket_power(amdsmi_processor_handle_all_cpu_across_socket[socket_index],
                                   &socket_power_watts)))
    readSuccess = true;
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Socket:%d, CpuSocketPowerWatt:%u\n", readSuccess ? "Success" : "Failed",
           socket_index, socket_power_watts);
  }

  return readSuccess ? socket_power_watts * 1000 : GOAMDSMI_UINT32_MAX;
}

uint32_t goamdsmi_cpu_socket_power_cap_get(uint32_t socket_index) {
  bool readSuccess = false;
  uint32_t socket_power_cap_watts = 0;
  if ((AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_cpu_socket_power_cap(amdsmi_processor_handle_all_cpu_across_socket[socket_index],
                                       &socket_power_cap_watts)))
    readSuccess = true;
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Socket:%d, CpuSocketPowerCapWatt:%u\n",
           readSuccess ? "Success" : "Failed", socket_index, socket_power_cap_watts);
  }

  return readSuccess ? socket_power_cap_watts * 1000 : GOAMDSMI_UINT32_MAX;
}

uint32_t goamdsmi_cpu_core_boostlimit_get(uint32_t thread_index) {
  bool readSuccess = false;
  uint32_t core_boostlimit_temp = GOAMDSMI_UINT32_MAX;
  uint32_t physicalCore_index = thread_index % num_cpu_physicalCore_inAllSocket;

#ifdef ENABLE_ESMI_LIB
  if (AMDSMI_STATUS_SUCCESS ==
      amdsmi_get_cpu_core_boostlimit(
          amdsmi_processor_handle_all_cpu_physicalCore_across_socket[physicalCore_index],
          &core_boostlimit_temp))
    readSuccess = true;
#endif
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Thread:%d PC:%d, CpuCoreBoostLimit:%lu\n",
           readSuccess ? "Success" : "Failed", thread_index, physicalCore_index,
           (unsigned long)(core_boostlimit_temp));
  }

  return core_boostlimit_temp;
}

////////////////////////////////////////////////------------GPU------------////////////////////////////////////////////////
bool goamdsmi_gpu_init() {
  bool gpu_init_success = false;
  if (GOAMDSMI_STATUS_SUCCESS == go_shim_amdsmiapu_init(GOAMDSMI_GPU_INIT)) {
    if ((num_gpu_devices_inAllSocket)) gpu_init_success = true;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s, InitAMDSMIGPUInit:%d, GpuSocketCount:%d, GpuCount:%d\n",
           gpu_init_success ? "Success" : "Failed", gpu_init_success ? 1 : 0, num_gpuSockets,
           num_gpu_devices_inAllSocket);
  }

  return gpu_init_success;
}

bool goamdsmi_gpu_shutdown() { return false; }

uint32_t goamdsmi_gpu_num_monitor_devices() {
  uint32_t gpu_num_monitor_devices = num_gpu_devices_inAllSocket;
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success, GpuNumMonitorDevices:%lu\n", (unsigned long)(gpu_num_monitor_devices));
  }
  return gpu_num_monitor_devices;
}

char* goamdsmi_gpu_dev_name_get(uint32_t dv_ind) {
  uint32_t len = 256;
  char* dev_name = (char*)malloc(sizeof(char) * len);
  dev_name[0] = '\0';
  strcpy(dev_name, GOAMDSMI_STRING_NA);

  return dev_name;
}

uint16_t goamdsmi_gpu_dev_id_get(uint32_t dv_ind) {
  bool readSuccess = false;
  uint16_t gpu_dev_id_temp = GOAMDSMI_UINT16_MAX;

  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_gpu_id(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                         &gpu_dev_id_temp)))
    readSuccess = true;
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuDevId:%d\n", readSuccess ? "Success" : "Failed", dv_ind,
           gpu_dev_id_temp);
  }

  return gpu_dev_id_temp;
}

uint64_t goamdsmi_gpu_dev_pci_id_get(uint32_t dv_ind) {
  uint64_t gpu_pci_id = GOAMDSMI_UINT64_MAX;
  return gpu_pci_id;
}

char* goamdsmi_gpu_dev_vendor_name_get(uint32_t dv_ind) {
  uint32_t len = 256;
  char* gpu_vendor_name = (char*)malloc(sizeof(char) * len);
  gpu_vendor_name[0] = '\0';
  strcpy(gpu_vendor_name, GOAMDSMI_STRING_NA);

  return gpu_vendor_name;
}

char* goamdsmi_gpu_dev_vbios_version_get(uint32_t dv_ind) {
  uint32_t len = 256;
  char* vbios_version = (char*)malloc(sizeof(char) * len);
  vbios_version[0] = '\0';
  strcpy(vbios_version, GOAMDSMI_STRING_NA);

  return vbios_version;
}

uint64_t goamdsmi_gpu_dev_power_cap_get(uint32_t dv_ind) {
  bool readSuccess = false;
  uint64_t gpu_power_cap = GOAMDSMI_UINT64_MAX;
  amdsmi_power_cap_info_t amdsmi_power_cap_info_temp = {0};

  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_power_cap_info(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                 GPU_SENSOR_0, &amdsmi_power_cap_info_temp))) {
    readSuccess = true;
    gpu_power_cap = amdsmi_power_cap_info_temp.power_cap;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuPowerCap:%llu, GpuPowerCapInWatt:%.6f\n",
           readSuccess ? "Success" : "Failed", dv_ind, (unsigned long long)(gpu_power_cap),
           ((double)(gpu_power_cap)) / 1000000);
  }
  return gpu_power_cap;
}

uint64_t goamdsmi_gpu_dev_power_get(uint32_t dv_ind) {
  uint64_t gpu_power = GOAMDSMI_UINT64_MAX;
  uint64_t gpu_power_temp = GOAMDSMI_UINT64_MAX;
  amdsmi_power_info_t amdsmi_power_info_temp = {0};

  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_power_info(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                             &amdsmi_power_info_temp))) {
    gpu_power_temp = amdsmi_power_info_temp.average_socket_power;
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
      printf("AMDSMI, Success for Gpu:%d, GpuPowerAverage:%llu, GpuPowerAverageinWatt:%.6f\n",
             dv_ind, (unsigned long long)(gpu_power_temp), ((double)(gpu_power_temp)) / 1000000);
    }

    if (MAX_GPU_POWER_FROM_DRIVER == gpu_power_temp) {
      gpu_power_temp = amdsmi_power_info_temp.current_socket_power;
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
        printf("AMDSMI, Success for Gpu:%d, GpuPowerCurrent:%llu, GpuPowerCurrentinWatt:%.6f\n",
               dv_ind, (unsigned long long)(gpu_power_temp), ((double)(gpu_power_temp)) / 1000000);
      }
    }
    gpu_power = gpu_power_temp;
    gpu_power = (gpu_power) * 1000000;  // to maintain backward compatibility with old ROCM SMI
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Success for Gpu:%d, GpuPower:%llu, GpuPowerinWatt:%.6f\n", dv_ind,
             (unsigned long long)(gpu_power), ((double)(gpu_power)) / 1000000);
    }
    return gpu_power;
  }

  amdsmi_gpu_metrics_t metrics = {0};
  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_gpu_metrics_info(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                   &metrics))) {
    gpu_power_temp = metrics.average_socket_power;
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
      printf(
          "AMDSMI, Success for Gpu:%d, GpuPowerAverageFromMetrics:%llu, "
          "GpuPowerAverageFromMetricsinWatt:%.6f\n",
          dv_ind, (unsigned long long)gpu_power_temp, ((double)(gpu_power_temp)) / 1000000);
    }

    if (MAX_GPU_POWER_FROM_DRIVER == gpu_power_temp) {
      gpu_power_temp = metrics.current_socket_power;
      if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_2)) {
        printf(
            "AMDSMI, Success for Gpu:%d, GpuPowerCurrentFromMetrics:%llu, "
            "GpuPowerCurrentFromMetricsinWatt:%.6f\n",
            dv_ind, (unsigned long long)gpu_power_temp, ((double)(gpu_power_temp)) / 1000000);
      }
    }
    gpu_power = gpu_power_temp;
    gpu_power = (gpu_power) * 1000000;  // to maintain backward compatibility with old ROCM SMI
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf(
          "AMDSMI, Success for Gpu:%d, GpuPowerFromMetrics:%llu, GpuPowerFromMetricsinWatt:%.6f\n",
          dv_ind, (unsigned long long)(gpu_power), ((double)(gpu_power)) / 1000000);
    }
    return gpu_power;
  }

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Failed for Gpu:%d, GpuPower:%llu, GpuPowerinWatt:%.6f\n", dv_ind,
           (unsigned long long)(gpu_power), ((double)(gpu_power)) / 1000000);
  }
  return gpu_power;
}

uint64_t goamdsmi_gpu_dev_temp_metric_get(uint32_t dv_ind, uint32_t sensor, uint32_t metric) {
  bool readSuccess = false;
  uint64_t gpu_temperature = GOAMDSMI_UINT64_MAX;
  int64_t gpu_temperature_temp = (int64_t)GOAMDSMI_UINT64_MAX;

  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_temp_metric(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind], sensor,
                              metric, &gpu_temperature_temp))) {
    readSuccess = true;
    gpu_temperature = (uint64_t)gpu_temperature_temp;
    gpu_temperature =
        (gpu_temperature) * 1000;  // to maintain backward compatibility with old ROCM SMI
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf(
          "AMDSMI, %s for Gpu:%d Sensor:%d Metric:%d, GpuTemperature:%llu, "
          "GpuTemperatureInDegree:%.3f\n",
          readSuccess ? "Success" : "Failed", dv_ind, sensor, metric,
          (unsigned long long)(gpu_temperature), ((double)(gpu_temperature)) / 1000);
    }
  }
  return gpu_temperature;
}

uint32_t goamdsmi_gpu_dev_overdrive_level_get(uint32_t dv_ind) {
  uint32_t gpu_overdrive_level = GOAMDSMI_UINT32_MAX;
  return gpu_overdrive_level;
}

uint32_t goamdsmi_gpu_dev_mem_overdrive_level_get(uint32_t dv_ind) {
  uint32_t gpu_mem_overdrive_level = GOAMDSMI_UINT32_MAX;
  return gpu_mem_overdrive_level;
}

uint32_t goamdsmi_gpu_dev_perf_level_get(uint32_t dv_ind) {
  uint32_t gpu_perf = GOAMDSMI_UINT32_MAX;
  return gpu_perf;
}

uint64_t goamdsmi_gpu_dev_gpu_clk_freq_get_sclk(uint32_t dv_ind) {
  bool readSuccess = false;
  uint64_t gpu_sclk_freq = GOAMDSMI_UINT64_MAX;
  amdsmi_frequencies_t freq = {0};

  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_clk_freq(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                           AMDSMI_CLK_TYPE_SYS, &freq))) {
    readSuccess = true;
    gpu_sclk_freq = freq.frequency[freq.current];
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuSclkFreq:%llu, GpuSclkFreqMhz:%.6f\n",
           readSuccess ? "Success" : "Failed", dv_ind, (unsigned long long)(gpu_sclk_freq),
           ((double)(gpu_sclk_freq)) / 1000000);
  }

  return gpu_sclk_freq;
}

uint64_t goamdsmi_gpu_dev_gpu_clk_freq_get_mclk(uint32_t dv_ind) {
  bool readSuccess = false;
  uint64_t gpu_memclk_freq = GOAMDSMI_UINT64_MAX;
  amdsmi_frequencies_t freq = {0};

  if ((dv_ind < num_gpu_devices_inAllSocket) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_clk_freq(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                           AMDSMI_CLK_TYPE_MEM, &freq))) {
    readSuccess = true;
    gpu_memclk_freq = freq.frequency[freq.current];
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuMclkFreq:%llu, GpuMclkFreqMhz:%.6f\n",
           readSuccess ? "Success" : "Failed", dv_ind, (unsigned long long)(gpu_memclk_freq),
           ((double)(gpu_memclk_freq)) / 1000000);
  }

  return gpu_memclk_freq;
}

uint64_t goamdsmi_gpu_od_volt_freq_range_min_get_sclk(uint32_t dv_ind) {
  uint64_t gpu_min_sclk = GOAMDSMI_UINT64_MAX;
  return gpu_min_sclk;
}

uint64_t goamdsmi_gpu_od_volt_freq_range_min_get_mclk(uint32_t dv_ind) {
  uint64_t gpu_min_memclk = GOAMDSMI_UINT64_MAX;
  return gpu_min_memclk;
}

uint64_t goamdsmi_gpu_od_volt_freq_range_max_get_sclk(uint32_t dv_ind) {
  uint64_t gpu_max_sclk = GOAMDSMI_UINT64_MAX;
  return gpu_max_sclk;
}

uint64_t goamdsmi_gpu_od_volt_freq_range_max_get_mclk(uint32_t dv_ind) {
  uint64_t gpu_max_memclk = GOAMDSMI_UINT64_MAX;
  return gpu_max_memclk;
}

uint32_t goamdsmi_gpu_dev_gpu_busy_percent_get(uint32_t dv_ind) {
  bool readSuccess = false;
  uint32_t gpu_busy_percent = GOAMDSMI_UINT32_MAX;
  amdsmi_engine_usage_t amdsmi_engine_usage_temp;

  if (AMDSMI_STATUS_SUCCESS ==
      amdsmi_get_gpu_activity(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                              &amdsmi_engine_usage_temp)) {
    readSuccess = true;
    gpu_busy_percent = amdsmi_engine_usage_temp.gfx_activity;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuBusyPerc:%lu\n", readSuccess ? "Success" : "Failed", dv_ind,
           (unsigned long)(gpu_busy_percent));
  }

  return gpu_busy_percent;
}

uint64_t goamdsmi_gpu_dev_gpu_memory_busy_percent_get(uint32_t dv_ind) {
  bool readSuccess = false;
  uint64_t gpu_memory_busy_percent = GOAMDSMI_UINT64_MAX;
  uint64_t gpu_memory_usage_temp = GOAMDSMI_UINT64_MAX;
  uint64_t gpu_memory_total_temp = GOAMDSMI_UINT64_MAX;

  if ((AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_gpu_memory_usage(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                   AMDSMI_MEM_TYPE_VRAM, &gpu_memory_usage_temp)) &&
      (AMDSMI_STATUS_SUCCESS ==
       amdsmi_get_gpu_memory_total(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                   AMDSMI_MEM_TYPE_VRAM, &gpu_memory_total_temp))) {
    readSuccess = true;
    gpu_memory_busy_percent = (uint64_t)(gpu_memory_usage_temp * 100) / gpu_memory_total_temp;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuMemoryBusyPerc:%llu\n", readSuccess ? "Success" : "Failed",
           dv_ind, (unsigned long long)(gpu_memory_busy_percent));
  }

  return gpu_memory_busy_percent;
}

uint64_t goamdsmi_gpu_dev_gpu_memory_usage_get(uint32_t dv_ind) {
  bool readSuccess = false;
  uint64_t gpu_memory_usage = GOAMDSMI_UINT64_MAX;
  uint64_t gpu_memory_usage_temp = GOAMDSMI_UINT64_MAX;

  if (AMDSMI_STATUS_SUCCESS ==
      amdsmi_get_gpu_memory_usage(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                  AMDSMI_MEM_TYPE_VRAM, &gpu_memory_usage_temp)) {
    readSuccess = true;
    gpu_memory_usage = (uint64_t)gpu_memory_usage_temp;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuMemoryUsage:%llu\n", readSuccess ? "Success" : "Failed",
           dv_ind, (unsigned long long)(gpu_memory_usage));
  }

  return gpu_memory_usage;
}

uint64_t goamdsmi_gpu_dev_gpu_memory_total_get(uint32_t dv_ind) {
  bool readSuccess = false;
  uint64_t gpu_memory_total = GOAMDSMI_UINT64_MAX;
  uint64_t gpu_memory_total_temp = GOAMDSMI_UINT64_MAX;

  if (AMDSMI_STATUS_SUCCESS ==
      amdsmi_get_gpu_memory_total(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                  AMDSMI_MEM_TYPE_VRAM, &gpu_memory_total_temp)) {
    readSuccess = true;
    gpu_memory_total = (uint64_t)gpu_memory_total_temp;
  }
  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, %s for Gpu:%d, GpuMemoryTotal:%llu\n", readSuccess ? "Success" : "Failed",
           dv_ind, (unsigned long long)(gpu_memory_total));
  }

  return gpu_memory_total;
}

// UMA carveout and TTM — kernel UAPI features, not libdrm.
// 256 == AMDSMI_MAX_STRING_LENGTH (amdsmi.h)
int32_t goamdsmi_gpu_uma_carveout_info_get(uint32_t dv_ind, uint32_t* current_index,
                                           uint32_t* num_options, char options[][256]) {
  amdsmi_uma_carveout_info_t uma_info;
  amdsmi_status_t status;

  if (dv_ind >= num_gpu_devices_inAllSocket) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed for Gpu:%d (invalid device index)\n", dv_ind);
    }
    return -1;
  }

  status = amdsmi_get_gpu_uma_carveout_info(
      amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind], &uma_info);

  if (status != AMDSMI_STATUS_SUCCESS) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed for Gpu:%d, Status:%d\n", dv_ind, status);
    }
    return -1;
  }

  *current_index = uma_info.current_index;
  *num_options = uma_info.num_options;

  for (uint32_t i = 0; i < uma_info.num_options && i < AMDSMI_MAX_CARVEOUT_OPTIONS; i++) {
    strncpy(options[i], uma_info.options[i].description, 255);
    options[i][255] = '\0';
  }

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success for Gpu:%d, CurrentIndex:%u, NumOptions:%u\n", dv_ind,
           uma_info.current_index, uma_info.num_options);
  }

  return 0;
}

int32_t goamdsmi_gpu_uma_carveout_set(uint32_t dv_ind, uint32_t option_index) {
  amdsmi_status_t status;

  if (dv_ind >= num_gpu_devices_inAllSocket) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed for Gpu:%d (invalid device index)\n", dv_ind);
    }
    return -1;
  }

  status = amdsmi_set_gpu_uma_carveout(amdsmi_processor_handle_all_gpu_device_across_socket[dv_ind],
                                       option_index);

  if (status != AMDSMI_STATUS_SUCCESS) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed for Gpu:%d, OptionIndex:%u, Status:%d\n", dv_ind, option_index,
             status);
    }
    return -1;
  }

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success for Gpu:%d, OptionIndex:%u\n", dv_ind, option_index);
  }

  return 0;
}

int32_t goamdsmi_ttm_info_get(uint64_t* current_pages) {
  amdsmi_ttm_info_t ttm_info;
  amdsmi_status_t status;

  status = amdsmi_get_ttm_info(&ttm_info);

  if (status != AMDSMI_STATUS_SUCCESS) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed to get TTM info, Status:%d\n", status);
    }
    return -1;
  }

  *current_pages = ttm_info.current_pages;

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success, CurrentPages:%llu\n", (unsigned long long)ttm_info.current_pages);
  }

  return 0;
}

int32_t goamdsmi_ttm_pages_limit_set(uint64_t pages) {
  amdsmi_status_t status;

  status = amdsmi_set_ttm_pages_limit(pages);

  if (status != AMDSMI_STATUS_SUCCESS) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed to set TTM pages limit, Pages:%llu, Status:%d\n",
             (unsigned long long)pages, status);
    }
    return -1;
  }

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success, Pages:%llu\n", (unsigned long long)pages);
  }

  return 0;
}

int32_t goamdsmi_ttm_pages_limit_reset(void) {
  amdsmi_status_t status;

  status = amdsmi_reset_ttm_pages_limit();

  if (status != AMDSMI_STATUS_SUCCESS) {
    if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
      printf("AMDSMI, Failed to reset TTM pages limit, Status:%d\n", status);
    }
    return -1;
  }

  if (enable_debug_level(GOAMDSMI_DEBUG_LEVEL_1)) {
    printf("AMDSMI, Success resetting TTM pages limit\n");
  }

  return 0;
}
