Remove union in hm_attrs_t; Remove code related to threshold_slowdown which will...
[hashcat.git] / src / hashcat.c
index 7fc6839..ec635e7 100644 (file)
@@ -411,7 +411,7 @@ const char *USAGE_BIG[] =
   #ifdef HAVE_HWMON
   "     --gpu-temp-abort          | Num  | Abort if GPU temperature reaches X degrees celsius   | --gpu-temp-abort=100",
   "     --gpu-temp-retain         | Num  | Try to retain GPU temperature at X degrees celsius   | --gpu-temp-retain=95",
-  "     --powertune-enable        |      | Enable automatic power tuning (AMD OverDrive 6 only) |",
+  "     --powertune-enable        |      | Enable power tuning, restores settings when finished |",
   #endif
   "     --scrypt-tmto             | Num  | Manually override TMTO value for scrypt to X         | --scrypt-tmto=3",
   " -s, --skip                    | Num  | Skip X words from the start                          | -s 1000000",
@@ -1547,8 +1547,7 @@ void status_display ()
       const int num_corespeed   = hm_get_corespeed_with_device_id   (device_id);
       const int num_memoryspeed = hm_get_memoryspeed_with_device_id (device_id);
       const int num_buslanes    = hm_get_buslanes_with_device_id    (device_id);
-      // not working
-      //const int num_throttle    = hm_get_throttle_with_device_id    (device_id);
+      const int num_throttle    = hm_get_throttle_with_device_id    (device_id);
 
       char output_buf[256] = { 0 };
 
@@ -1596,14 +1595,12 @@ void status_display ()
         output_len = strlen (output_buf);
       }
 
-      /*
-      if (num_throttle >= 0)
+      if (num_throttle == 1)
       {
-        snprintf (output_buf + output_len, sizeof (output_buf) - output_len, " Throttle:%u", num_throttle);
+        snprintf (output_buf + output_len, sizeof (output_buf) - output_len, " *Throttled*");
 
         output_len = strlen (output_buf);
       }
-      */
 
       if (output_len == 0)
       {
@@ -2423,7 +2420,7 @@ static float find_kernel_power_div (const u64 total_left, const uint kernel_powe
     fflush (stdout);
   }
 
-  if ((kernel_power_all * kernel_power_div) < 8) return 1;
+  //if ((kernel_power_all * kernel_power_div) < 8) return 1;
 
   return kernel_power_div;
 }
@@ -2908,7 +2905,7 @@ static void run_copy (hc_device_param_t *device_param, const uint pws_cnt)
 
 static double try_run (hc_device_param_t *device_param, const u32 kernel_accel, const u32 kernel_loops)
 {
-  const u32 kernel_power = device_param->device_processors * device_param->kernel_threads * kernel_accel;
+  const u32 kernel_power_try = device_param->device_processors * device_param->kernel_threads * kernel_accel;
 
   device_param->kernel_params_buf32[25] = 0;
   device_param->kernel_params_buf32[26] = kernel_loops; // not a bug, both need to be set
@@ -2916,11 +2913,11 @@ static double try_run (hc_device_param_t *device_param, const u32 kernel_accel,
 
   if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
   {
-    run_kernel (KERN_RUN_1, device_param, kernel_power, true);
+    run_kernel (KERN_RUN_1, device_param, kernel_power_try, true);
   }
   else
   {
-    run_kernel (KERN_RUN_2, device_param, kernel_power, true);
+    run_kernel (KERN_RUN_2, device_param, kernel_power_try, true);
   }
 
   const double exec_ms_prev = get_avg_exec_time (device_param, 1);
@@ -2980,15 +2977,17 @@ static void autotune (hc_device_param_t *device_param)
       device_param->pws_buf[i].pw_len = 7 + (i & 7);
     }
 
+    hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_buf, CL_TRUE, 0, kernel_power_max * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
+  }
+
+  if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
+  {
     if (data.kernel_rules_cnt > 1)
     {
-      hc_clEnqueueCopyBuffer (data.ocl, device_param->command_queue, device_param->d_rules, device_param->d_rules_c, 0, 0, kernel_loops_max * sizeof (kernel_rule_t), 0, NULL, NULL);
+      hc_clEnqueueCopyBuffer (data.ocl, device_param->command_queue, device_param->d_rules, device_param->d_rules_c, 0, 0, MIN (kernel_loops_max, KERNEL_RULES) * sizeof (kernel_rule_t), 0, NULL, NULL);
     }
-
-    hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_buf, CL_TRUE, 0, kernel_power_max * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
   }
-
-  if (data.attack_exec == ATTACK_EXEC_OUTSIDE_KERNEL)
+  else
   {
     run_kernel_amp (device_param, kernel_power_max);
   }
@@ -3819,8 +3818,6 @@ static void *thread_monitor (void *p)
   #ifdef HAVE_HWMON
   uint hwmon_check   = 0;
 
-  int slowdown_warnings = 0;
-
   // these variables are mainly used for fan control
 
   int *fan_speed_chgd = (int *) mycalloc (data.devices_cnt, sizeof (int));
@@ -3885,50 +3882,6 @@ static void *thread_monitor (void *p)
 
     #ifdef HAVE_HWMON
 
-    if (1)
-    {
-      hc_thread_mutex_lock (mux_adl);
-
-      for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
-      {
-        hc_device_param_t *device_param = &data.devices_param[device_id];
-
-        if (device_param->skipped) continue;
-
-        if ((data.devices_param[device_id].device_type & CL_DEVICE_TYPE_GPU) == 0) continue;
-
-        const int temperature = hm_get_temperature_with_device_id (device_id);
-
-        const int threshold = data.hm_device[device_id].gpu_temp_threshold_slowdown;
-
-        if (temperature >= threshold)
-        {
-          if (slowdown_warnings < 3)
-          {
-            if (data.quiet == 0) clear_prompt ();
-
-            log_info ("WARNING: Drivers temperature threshold (%dc) hit on GPU #%d, expect performance to drop...", threshold, device_id + 1);
-
-            if (slowdown_warnings == 2)
-            {
-              log_info ("");
-            }
-
-            if (data.quiet == 0) fprintf (stdout, "%s", PROMPT);
-            if (data.quiet == 0) fflush (stdout);
-
-            slowdown_warnings++;
-          }
-        }
-        else
-        {
-          slowdown_warnings = 0;
-        }
-      }
-
-      hc_thread_mutex_unlock (mux_adl);
-    }
-
     if (hwmon_check == 1)
     {
       hc_thread_mutex_lock (mux_adl);
@@ -4006,13 +3959,11 @@ static void *thread_monitor (void *p)
                 {
                   if (device_param->device_vendor_id == VENDOR_ID_AMD)
                   {
-                    hm_set_fanspeed_with_device_id_amd (device_id, fan_speed_new, 1);
+                    hm_set_fanspeed_with_device_id_adl (device_id, fan_speed_new, 1);
                   }
                   else if (device_param->device_vendor_id == VENDOR_ID_NV)
                   {
-                    #ifdef _WIN
-                    hm_set_fanspeed_with_device_id_nvapi (device_id, fan_speed_new, 1);
-                    #endif
+
                   }
 
                   fan_speed_chgd[device_id] = 1;
@@ -4412,8 +4363,8 @@ static void *thread_outfile_remove (void *p)
 
 static void pw_add (hc_device_param_t *device_param, const u8 *pw_buf, const int pw_len)
 {
-  if (device_param->pws_cnt < device_param->kernel_power)
-  {
+  //if (device_param->pws_cnt < device_param->kernel_power)
+  //{
     pw_t *pw = (pw_t *) device_param->pws_buf + device_param->pws_cnt;
 
     u8 *ptr = (u8 *) pw->i;
@@ -4425,16 +4376,26 @@ static void pw_add (hc_device_param_t *device_param, const u8 *pw_buf, const int
     pw->pw_len = pw_len;
 
     device_param->pws_cnt++;
-  }
-  else
-  {
-    fprintf (stderr, "BUG pw_add()!!\n");
+  //}
+  //else
+  //{
+  //  fprintf (stderr, "BUG pw_add()!!\n");
+  //
+  //  return;
+  //}
+}
 
-    return;
+static u32 get_power (const u32 kernel_power)
+{
+  if (data.kernel_power_div)
+  {
+    return (float) kernel_power * data.kernel_power_div;
   }
+
+  return kernel_power;
 }
 
-static uint get_work (hc_device_param_t *device_param, const u64 max, const bool allow_div)
+static uint get_work (hc_device_param_t *device_param, const u64 max)
 {
   hc_thread_mutex_lock (mux_dispatcher);
 
@@ -4445,31 +4406,15 @@ static uint get_work (hc_device_param_t *device_param, const u64 max, const bool
 
   const u64 words_left = words_base - words_cur;
 
-  if (allow_div)
+  if (data.kernel_power_all > words_left)
   {
-    if (data.kernel_power_all > words_left)
+    if (data.kernel_power_div == 0)
     {
-      if (data.kernel_power_div == 0)
-      {
-        data.kernel_power_div = find_kernel_power_div (words_left, data.kernel_power_all);
-      }
-    }
-
-    if (data.kernel_power_div)
-    {
-      if (device_param->kernel_power == device_param->kernel_power_user)
-      {
-        const u32 kernel_power_new = (float) device_param->kernel_power * data.kernel_power_div;
-
-        if (kernel_power_new < device_param->kernel_power)
-        {
-          device_param->kernel_power = kernel_power_new;
-        }
-      }
+      data.kernel_power_div = find_kernel_power_div (words_left, data.kernel_power_all);
     }
   }
 
-  const uint kernel_power = device_param->kernel_power;
+  const u32 kernel_power = get_power (device_param->kernel_power);
 
   uint work = MIN (words_left, kernel_power);
 
@@ -4482,7 +4427,7 @@ static uint get_work (hc_device_param_t *device_param, const u64 max, const bool
   return work;
 }
 
-static void *thread_calc_stdin (void *p)
+static void *thread_autotune (void *p)
 {
   hc_device_param_t *device_param = (hc_device_param_t *) p;
 
@@ -4490,12 +4435,19 @@ static void *thread_calc_stdin (void *p)
 
   autotune (device_param);
 
+  return NULL;
+}
+
+static void *thread_calc_stdin (void *p)
+{
+  hc_device_param_t *device_param = (hc_device_param_t *) p;
+
+  if (device_param->skipped) return NULL;
+
   char *buf = (char *) mymalloc (HCBUFSIZ);
 
   const uint attack_kern = data.attack_kern;
 
-  const uint kernel_power = device_param->kernel_power;
-
   while ((data.devices_status != STATUS_EXHAUSTED) && (data.devices_status != STATUS_CRACKED) && (data.devices_status != STATUS_ABORTED) && (data.devices_status != STATUS_QUIT))
   {
     hc_thread_mutex_lock (mux_dispatcher);
@@ -4509,7 +4461,7 @@ static void *thread_calc_stdin (void *p)
 
     uint words_cur = 0;
 
-    while (words_cur < kernel_power)
+    while (words_cur < get_power (device_param->kernel_power))
     {
       char *line_buf = fgets (buf, HCBUFSIZ - 1, stdin);
 
@@ -4636,8 +4588,6 @@ static void *thread_calc (void *p)
 
   if (device_param->skipped) return NULL;
 
-  autotune (device_param);
-
   const uint attack_mode = data.attack_mode;
   const uint attack_kern = data.attack_kern;
 
@@ -4645,7 +4595,7 @@ static void *thread_calc (void *p)
   {
     while ((data.devices_status != STATUS_EXHAUSTED) && (data.devices_status != STATUS_CRACKED) && (data.devices_status != STATUS_ABORTED) && (data.devices_status != STATUS_QUIT))
     {
-      const uint work = get_work (device_param, -1, true);
+      const uint work = get_work (device_param, -1);
 
       if (work == 0) break;
 
@@ -4760,18 +4710,16 @@ static void *thread_calc (void *p)
       u64 words_off = 0;
       u64 words_fin = 0;
 
-      bool allow_div = true;
-
       u64 max = -1;
 
       while (max)
       {
-        const uint work = get_work (device_param, max, allow_div);
-
-        allow_div = false;
+        const uint work = get_work (device_param, max);
 
         if (work == 0) break;
 
+        max = 0;
+
         words_off = device_param->words_off;
         words_fin = words_off + work;
 
@@ -4780,8 +4728,6 @@ static void *thread_calc (void *p)
 
         for ( ; words_cur < words_off; words_cur++) get_next_word (wl_data, fd, &line_buf, &line_len);
 
-        max = 0;
-
         for ( ; words_cur < words_fin; words_cur++)
         {
           get_next_word (wl_data, fd, &line_buf, &line_len);
@@ -5443,8 +5389,8 @@ void SetConsoleWindowSize (const int x)
 
   COORD co;
 
-  co.X = sr->Right  + 1;
-  co.Y = sr->Bottom + 1;
+  co.X = sr->Right + 1;
+  co.Y = 9999;
 
   if (!SetConsoleScreenBufferSize (h, co)) return;
 
@@ -13326,6 +13272,10 @@ int main (int argc, char **argv)
      * OpenCL devices: simply push all devices from all platforms into the same device array
      */
 
+    int need_adl   = 0;
+    int need_nvapi = 0;
+    int need_nvml  = 0;
+
     hc_device_param_t *devices_param = (hc_device_param_t *) mycalloc (DEVICES_MAX, sizeof (hc_device_param_t));
 
     data.devices_param = devices_param;
@@ -13582,7 +13532,7 @@ int main (int argc, char **argv)
 
         if (device_endian_little == CL_FALSE)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: not little endian device", device_id + 1);
+          log_info ("Device #%u: WARNING: not little endian device", device_id + 1);
 
           device_param->skipped = 1;
         }
@@ -13595,7 +13545,7 @@ int main (int argc, char **argv)
 
         if (device_available == CL_FALSE)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: device not available", device_id + 1);
+          log_info ("Device #%u: WARNING: device not available", device_id + 1);
 
           device_param->skipped = 1;
         }
@@ -13608,7 +13558,7 @@ int main (int argc, char **argv)
 
         if (device_compiler_available == CL_FALSE)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: device no compiler available", device_id + 1);
+          log_info ("Device #%u: WARNING: device no compiler available", device_id + 1);
 
           device_param->skipped = 1;
         }
@@ -13621,7 +13571,7 @@ int main (int argc, char **argv)
 
         if ((device_execution_capabilities & CL_EXEC_KERNEL) == 0)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: device does not support executing kernels", device_id + 1);
+          log_info ("Device #%u: WARNING: device does not support executing kernels", device_id + 1);
 
           device_param->skipped = 1;
         }
@@ -13638,14 +13588,14 @@ int main (int argc, char **argv)
 
         if (strstr (device_extensions, "base_atomics") == 0)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: device does not support base atomics", device_id + 1);
+          log_info ("Device #%u: WARNING: device does not support base atomics", device_id + 1);
 
           device_param->skipped = 1;
         }
 
         if (strstr (device_extensions, "byte_addressable_store") == 0)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: device does not support byte addressable store", device_id + 1);
+          log_info ("Device #%u: WARNING: device does not support byte addressable store", device_id + 1);
 
           device_param->skipped = 1;
         }
@@ -13660,7 +13610,7 @@ int main (int argc, char **argv)
 
         if (device_local_mem_size < 32768)
         {
-          if (data.quiet == 0) log_info ("Device #%u: WARNING: device local mem size is too small", device_id + 1);
+          log_info ("Device #%u: WARNING: device local mem size is too small", device_id + 1);
 
           device_param->skipped = 1;
         }
@@ -13675,9 +13625,13 @@ int main (int argc, char **argv)
         {
           if (device_param->device_vendor_id == VENDOR_ID_AMD_USE_INTEL)
           {
-            if (data.quiet == 0) log_info ("Device #%u: WARNING: not native intel opencl platform", device_id + 1);
+            if (data.force == 0)
+            {
+              log_info ("Device #%u: WARNING: not native intel opencl runtime, expect massive speed loss", device_id + 1);
+              log_info ("           You can use --force to override this but do not post error reports if you do so");
 
-            device_param->skipped = 1;
+              device_param->skipped = 1;
+            }
           }
         }
 
@@ -13716,6 +13670,25 @@ int main (int argc, char **argv)
 
         // device_processor_cores
 
+        if (device_param->device_type & CL_DEVICE_TYPE_GPU)
+        {
+          if ((device_param->platform_vendor_id == VENDOR_ID_AMD) && (device_param->device_vendor_id == VENDOR_ID_AMD))
+          {
+            need_adl = 1;
+          }
+
+          if ((device_param->platform_vendor_id == VENDOR_ID_NV) && (device_param->device_vendor_id == VENDOR_ID_NV))
+          {
+            need_nvml = 1;
+
+            #ifdef _WIN
+            need_nvapi = 1;
+            #endif
+          }
+        }
+
+        // device_processor_cores
+
         if (device_type & CL_DEVICE_TYPE_CPU)
         {
           cl_uint device_processor_cores = 1;
@@ -13985,95 +13958,93 @@ int main (int argc, char **argv)
      */
 
     #ifdef HAVE_HWMON
-    hm_attrs_t hm_adapters_nv[DEVICES_MAX]  = { { { 0 }, 0, 0, 0, 0, 0 } };
-    hm_attrs_t hm_adapters_amd[DEVICES_MAX] = { { { 0 }, 0, 0, 0, 0, 0 } };
+    hm_attrs_t hm_adapters_adl[DEVICES_MAX]   = { { 0 } };
+    hm_attrs_t hm_adapters_nvapi[DEVICES_MAX] = { { 0 } };
+    hm_attrs_t hm_adapters_nvml[DEVICES_MAX]  = { { 0 } };
 
     if (gpu_temp_disable == 0)
     {
-      #if defined(WIN)
+      ADL_PTR   *adl   = (ADL_PTR *)   mymalloc (sizeof (ADL_PTR));
       NVAPI_PTR *nvapi = (NVAPI_PTR *) mymalloc (sizeof (NVAPI_PTR));
+      NVML_PTR  *nvml  = (NVML_PTR *)  mymalloc (sizeof (NVML_PTR));
 
-      if (nvapi_init (nvapi) == 0)
-        data.hm_nv = nvapi;
+      data.hm_adl   = NULL;
+      data.hm_nvapi = NULL;
+      data.hm_nvml  = NULL;
+
+      if ((need_nvml == 1) && (nvml_init (nvml) == 0))
+      {
+        data.hm_nvml = nvml;
+      }
 
-      if (data.hm_nv)
+      if (data.hm_nvml)
       {
-        if (hm_NvAPI_Initialize (data.hm_nv) == NVAPI_OK)
+        if (hm_NVML_nvmlInit (data.hm_nvml) == NVML_SUCCESS)
         {
-          HM_ADAPTER_NV nvGPUHandle[DEVICES_MAX] = { 0 };
+          HM_ADAPTER_NVML nvmlGPUHandle[DEVICES_MAX] = { 0 };
 
-          int tmp_in = hm_get_adapter_index_nv (nvGPUHandle);
+          int tmp_in = hm_get_adapter_index_nvml (nvmlGPUHandle);
 
           int tmp_out = 0;
 
           for (int i = 0; i < tmp_in; i++)
           {
-            hm_adapters_nv[tmp_out++].adapter_index.nv = nvGPUHandle[i];
+            hm_adapters_nvml[tmp_out++].nvml = nvmlGPUHandle[i];
           }
 
           for (int i = 0; i < tmp_out; i++)
           {
-            NV_GPU_COOLER_SETTINGS pCoolerSettings;
+            unsigned int speed;
+
+            if (hm_NVML_nvmlDeviceGetFanSpeed (data.hm_nvml, 0, hm_adapters_nvml[i].nvml, &speed) == NVML_SUCCESS) hm_adapters_nvml[i].fan_get_supported = 1;
 
-            pCoolerSettings.Version = GPU_COOLER_SETTINGS_VER | sizeof (NV_GPU_COOLER_SETTINGS);
+            hm_NVML_nvmlDeviceSetComputeMode (data.hm_nvml, 1, hm_adapters_nvml[i].nvml, NVML_COMPUTEMODE_EXCLUSIVE_PROCESS);
 
-            if (hm_NvAPI_GPU_GetCoolerSettings (data.hm_nv, hm_adapters_nv[i].adapter_index.nv, 0, &pCoolerSettings) != NVAPI_NOT_SUPPORTED) hm_adapters_nv[i].fan_get_supported = 1;
+            hm_NVML_nvmlDeviceSetGpuOperationMode (data.hm_nvml, 1, hm_adapters_nvml[i].nvml, NVML_GOM_ALL_ON);
           }
         }
       }
-      #endif // WIN
 
-      #if defined(LINUX)
-      NVML_PTR *nvml = (NVML_PTR *) mymalloc (sizeof (NVML_PTR));
-
-      if (nvml_init (nvml) == 0)
-        data.hm_nv = nvml;
+      if ((need_nvapi == 1) && (nvapi_init (nvapi) == 0))
+      {
+        data.hm_nvapi = nvapi;
+      }
 
-      if (data.hm_nv)
+      if (data.hm_nvapi)
       {
-        if (hm_NVML_nvmlInit (data.hm_nv) == NVML_SUCCESS)
+        if (hm_NvAPI_Initialize (data.hm_nvapi) == NVAPI_OK)
         {
-          HM_ADAPTER_NV nvGPUHandle[DEVICES_MAX] = { 0 };
+          HM_ADAPTER_NVAPI nvGPUHandle[DEVICES_MAX] = { 0 };
 
-          int tmp_in = hm_get_adapter_index_nv (nvGPUHandle);
+          int tmp_in = hm_get_adapter_index_nvapi (nvGPUHandle);
 
           int tmp_out = 0;
 
           for (int i = 0; i < tmp_in; i++)
           {
-            hm_adapters_nv[tmp_out++].adapter_index.nv = nvGPUHandle[i];
-          }
-
-          for (int i = 0; i < tmp_out; i++)
-          {
-            unsigned int speed;
-
-            if (hm_NVML_nvmlDeviceGetFanSpeed (data.hm_nv, 1, hm_adapters_nv[i].adapter_index.nv, &speed) != NVML_ERROR_NOT_SUPPORTED) hm_adapters_nv[i].fan_get_supported = 1;
+            hm_adapters_nvapi[tmp_out++].nvapi = nvGPUHandle[i];
           }
         }
       }
-      #endif // LINUX
-
-      data.hm_amd = NULL;
-
-      ADL_PTR *adl = (ADL_PTR *) mymalloc (sizeof (ADL_PTR));
 
-      if (adl_init (adl) == 0)
-        data.hm_amd = adl;
+      if ((need_adl == 1) && (adl_init (adl) == 0))
+      {
+        data.hm_adl = adl;
+      }
 
-      if (data.hm_amd)
+      if (data.hm_adl)
       {
-        if (hm_ADL_Main_Control_Create (data.hm_amd, ADL_Main_Memory_Alloc, 0) == ADL_OK)
+        if (hm_ADL_Main_Control_Create (data.hm_adl, ADL_Main_Memory_Alloc, 0) == ADL_OK)
         {
           // total number of adapters
 
           int hm_adapters_num;
 
-          if (get_adapters_num_amd (data.hm_amd, &hm_adapters_num) != 0) return (-1);
+          if (get_adapters_num_adl (data.hm_adl, &hm_adapters_num) != 0) return (-1);
 
           // adapter info
 
-          LPAdapterInfo lpAdapterInfo = hm_get_adapter_info_amd (data.hm_amd, hm_adapters_num);
+          LPAdapterInfo lpAdapterInfo = hm_get_adapter_info_adl (data.hm_adl, hm_adapters_num);
 
           if (lpAdapterInfo == NULL) return (-1);
 
@@ -14087,12 +14058,12 @@ int main (int argc, char **argv)
           {
             hc_thread_mutex_lock (mux_adl);
 
-            // hm_get_opencl_busid_devid (hm_adapters_amd, devices_all_cnt, devices_all);
+            // hm_get_opencl_busid_devid (hm_adapters_adl, devices_all_cnt, devices_all);
 
-            hm_get_adapter_index_amd (hm_adapters_amd, valid_adl_device_list, num_adl_adapters, lpAdapterInfo);
+            hm_get_adapter_index_adl (hm_adapters_adl, valid_adl_device_list, num_adl_adapters, lpAdapterInfo);
 
-            hm_get_overdrive_version  (data.hm_amd, hm_adapters_amd, valid_adl_device_list, num_adl_adapters, lpAdapterInfo);
-            hm_check_fanspeed_control (data.hm_amd, hm_adapters_amd, valid_adl_device_list, num_adl_adapters, lpAdapterInfo);
+            hm_get_overdrive_version  (data.hm_adl, hm_adapters_adl, valid_adl_device_list, num_adl_adapters, lpAdapterInfo);
+            hm_check_fanspeed_control (data.hm_adl, hm_adapters_adl, valid_adl_device_list, num_adl_adapters, lpAdapterInfo);
 
             hc_thread_mutex_unlock (mux_adl);
           }
@@ -14102,7 +14073,7 @@ int main (int argc, char **argv)
         }
       }
 
-      if (data.hm_amd == NULL && data.hm_nv == NULL)
+      if (data.hm_adl == NULL && data.hm_nvml == NULL)
       {
         gpu_temp_disable = 1;
       }
@@ -14119,6 +14090,8 @@ int main (int argc, char **argv)
 
     int *od_power_control_status = (int *) mycalloc (data.devices_cnt, sizeof (int));
 
+    unsigned int *nvml_power_limit = (unsigned int *) mycalloc (data.devices_cnt, sizeof (unsigned int));
+
     /**
      * User-defined GPU temp handling
      */
@@ -14189,7 +14162,7 @@ int main (int argc, char **argv)
        */
 
       #ifdef HAVE_HWMON
-      if (gpu_temp_disable == 0 && data.hm_amd == NULL && data.hm_nv == NULL)
+      if (gpu_temp_disable == 0 && data.hm_adl == NULL && data.hm_nvml == NULL)
       {
         log_info ("Watchdog: Hardware Monitoring Interface not found on your system");
       }
@@ -14236,22 +14209,18 @@ int main (int argc, char **argv)
 
         if (device_param->device_vendor_id == VENDOR_ID_NV)
         {
-          memcpy (&data.hm_device[device_id], &hm_adapters_nv[platform_devices_id], sizeof (hm_attrs_t));
+          memcpy (&data.hm_device[device_id], &hm_adapters_nvml[platform_devices_id], sizeof (hm_attrs_t));
         }
 
         if (device_param->device_vendor_id == VENDOR_ID_AMD)
         {
-          memcpy (&data.hm_device[device_id], &hm_adapters_amd[platform_devices_id], sizeof (hm_attrs_t));
+          memcpy (&data.hm_device[device_id], &hm_adapters_adl[platform_devices_id], sizeof (hm_attrs_t));
         }
       }
     }
 
     /**
-     * Temporary fix:
-     * with AMD r9 295x cards it seems that we need to set the powertune value just AFTER the ocl init stuff
-     * otherwise after hc_clCreateContext () etc, powertune value was set back to "normal" and cards unfortunately
-     * were not working @ full speed (setting hm_ADL_Overdrive_PowerControl_Set () here seems to fix the problem)
-     * Driver / ADL bug?
+     * powertune on user request
      */
 
     if (powertune_enable == 1)
@@ -14264,38 +14233,177 @@ int main (int argc, char **argv)
 
         if (device_param->skipped) continue;
 
-        if (data.hm_device[device_id].od_version == 6)
+        if (data.devices_param[device_id].device_vendor_id == VENDOR_ID_AMD)
         {
-          // set powertune value only
-
-          int powertune_supported = 0;
-
-          int ADL_rc = 0;
+          /**
+           * Temporary fix:
+           * with AMD r9 295x cards it seems that we need to set the powertune value just AFTER the ocl init stuff
+           * otherwise after hc_clCreateContext () etc, powertune value was set back to "normal" and cards unfortunately
+           * were not working @ full speed (setting hm_ADL_Overdrive_PowerControl_Set () here seems to fix the problem)
+           * Driver / ADL bug?
+           */
 
-          if ((ADL_rc = hm_ADL_Overdrive6_PowerControl_Caps (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &powertune_supported)) != ADL_OK)
+          if (data.hm_device[device_id].od_version == 6)
           {
-            log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
+            int ADL_rc;
 
-            return (-1);
-          }
+            // check powertune capabilities first, if not available then skip device
 
-          if (powertune_supported != 0)
-          {
-            // powertune set
-            ADLOD6PowerControlInfo powertune = {0, 0, 0, 0, 0};
+            int powertune_supported = 0;
 
-            if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &powertune)) != ADL_OK)
+            if ((ADL_rc = hm_ADL_Overdrive6_PowerControl_Caps (data.hm_adl, data.hm_device[device_id].adl, &powertune_supported)) != ADL_OK)
             {
-              log_error ("ERROR: Failed to get current ADL PowerControl settings");
+              log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
 
               return (-1);
             }
 
-            if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_amd, data.hm_device[device_id].adapter_index.amd, powertune.iMaxValue)) != ADL_OK)
+            // first backup current value, we will restore it later
+
+            if (powertune_supported != 0)
             {
-              log_error ("ERROR: Failed to set new ADL PowerControl values");
+              // powercontrol settings
 
-              return (-1);
+              ADLOD6PowerControlInfo powertune = {0, 0, 0, 0, 0};
+
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_adl, data.hm_device[device_id].adl, &powertune)) == ADL_OK)
+              {
+                ADL_rc = hm_ADL_Overdrive_PowerControl_Get (data.hm_adl, data.hm_device[device_id].adl, &od_power_control_status[device_id]);
+              }
+
+              if (ADL_rc != ADL_OK)
+              {
+                log_error ("ERROR: Failed to get current ADL PowerControl settings");
+
+                return (-1);
+              }
+
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adl, powertune.iMaxValue)) != ADL_OK)
+              {
+                log_error ("ERROR: Failed to set new ADL PowerControl values");
+
+                return (-1);
+              }
+
+              // clocks
+
+              memset (&od_clock_mem_status[device_id], 0, sizeof (ADLOD6MemClockState));
+
+              od_clock_mem_status[device_id].state.iNumberOfPerformanceLevels = 2;
+
+              if ((ADL_rc = hm_ADL_Overdrive_StateInfo_Get (data.hm_adl, data.hm_device[device_id].adl, ADL_OD6_GETSTATEINFO_CUSTOM_PERFORMANCE, &od_clock_mem_status[device_id])) != ADL_OK)
+              {
+                log_error ("ERROR: Failed to get ADL memory and engine clock frequency");
+
+                return (-1);
+              }
+
+              // Query capabilities only to see if profiles were not "damaged", if so output a warning but do accept the users profile settings
+
+              ADLOD6Capabilities caps = {0, 0, 0, {0, 0, 0}, {0, 0, 0}, 0, 0};
+
+              if ((ADL_rc = hm_ADL_Overdrive_Capabilities_Get (data.hm_adl, data.hm_device[device_id].adl, &caps)) != ADL_OK)
+              {
+                log_error ("ERROR: Failed to get ADL device capabilities");
+
+                return (-1);
+              }
+
+              int engine_clock_max = caps.sEngineClockRange.iMax * 0.6666;
+              int memory_clock_max = caps.sMemoryClockRange.iMax * 0.6250;
+
+              int warning_trigger_engine = (int) (0.25 * (float) engine_clock_max);
+              int warning_trigger_memory = (int) (0.25 * (float) memory_clock_max);
+
+              int engine_clock_profile_max = od_clock_mem_status[device_id].state.aLevels[1].iEngineClock;
+              int memory_clock_profile_max = od_clock_mem_status[device_id].state.aLevels[1].iMemoryClock;
+
+              // warning if profile has too low max values
+
+              if ((engine_clock_max - engine_clock_profile_max) > warning_trigger_engine)
+              {
+                log_info ("WARN: the custom profile seems to have too low maximum engine clock values. You therefore may not reach full performance");
+              }
+
+              if ((memory_clock_max - memory_clock_profile_max) > warning_trigger_memory)
+              {
+                log_info ("WARN: the custom profile seems to have too low maximum memory clock values. You therefore may not reach full performance");
+              }
+
+              ADLOD6StateInfo *performance_state = (ADLOD6StateInfo*) mycalloc (1, sizeof (ADLOD6StateInfo) + sizeof (ADLOD6PerformanceLevel));
+
+              performance_state->iNumberOfPerformanceLevels = 2;
+
+              performance_state->aLevels[0].iEngineClock = engine_clock_profile_max;
+              performance_state->aLevels[1].iEngineClock = engine_clock_profile_max;
+              performance_state->aLevels[0].iMemoryClock = memory_clock_profile_max;
+              performance_state->aLevels[1].iMemoryClock = memory_clock_profile_max;
+
+              if ((ADL_rc = hm_ADL_Overdrive_State_Set (data.hm_adl, data.hm_device[device_id].adl, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
+              {
+                log_info ("ERROR: Failed to set ADL performance state");
+
+                return (-1);
+              }
+
+              local_free (performance_state);
+            }
+
+            // set powertune value only
+
+            if (powertune_supported != 0)
+            {
+              // powertune set
+              ADLOD6PowerControlInfo powertune = {0, 0, 0, 0, 0};
+
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_adl, data.hm_device[device_id].adl, &powertune)) != ADL_OK)
+              {
+                log_error ("ERROR: Failed to get current ADL PowerControl settings");
+
+                return (-1);
+              }
+
+              if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adl, powertune.iMaxValue)) != ADL_OK)
+              {
+                log_error ("ERROR: Failed to set new ADL PowerControl values");
+
+                return (-1);
+              }
+            }
+          }
+        }
+
+        if (data.devices_param[device_id].device_vendor_id == VENDOR_ID_NV)
+        {
+          // first backup current value, we will restore it later
+
+          unsigned int limit;
+
+          int powertune_supported = 0;
+
+          if (hm_NVML_nvmlDeviceGetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].nvml, &limit) == NVML_SUCCESS)
+          {
+            powertune_supported = 1;
+          }
+
+          // if backup worked, activate the maximum allowed
+
+          if (powertune_supported != 0)
+          {
+            unsigned int minLimit;
+            unsigned int maxLimit;
+
+            if (hm_NVML_nvmlDeviceGetPowerManagementLimitConstraints (data.hm_nvml, 0, data.hm_device[device_id].nvml, &minLimit, &maxLimit) == NVML_SUCCESS)
+            {
+              if (maxLimit > 0)
+              {
+                if (hm_NVML_nvmlDeviceSetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].nvml, maxLimit) == NVML_SUCCESS)
+                {
+                  // now we can be sure we need to reset later
+
+                  nvml_power_limit[device_id] = limit;
+                }
+              }
             }
           }
         }
@@ -14312,8 +14420,6 @@ int main (int argc, char **argv)
 
     if (data.quiet == 0) log_info_nn ("Initializing device kernels and memory...");
 
-    uint kernel_power_all = 0;
-
     for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
     {
       /**
@@ -14374,6 +14480,8 @@ int main (int argc, char **argv)
       if (hash_mode == 10500) kernel_threads = 64; // RC4
       if (hash_mode == 13100) kernel_threads = 64; // RC4
 
+      device_param->kernel_threads = kernel_threads;
+
       /**
        * create input buffers on device : calculate size of fixed memory buffers
        */
@@ -14743,15 +14851,6 @@ int main (int argc, char **argv)
       device_param->size_tmps    = size_tmps;
       device_param->size_hooks   = size_hooks;
 
-      // do not confuse kernel_accel_max with kernel_accel here
-
-      const u32 kernel_power = device_processors * kernel_threads * kernel_accel_max;
-
-      device_param->kernel_threads    = kernel_threads;
-      device_param->kernel_power_user = kernel_power;
-
-      kernel_power_all += kernel_power;
-
       /**
        * default building options
        */
@@ -15593,17 +15692,6 @@ int main (int argc, char **argv)
 
       #if defined(HAVE_HWMON)
 
-      /**
-       * Store thermal target temperature so we can send a notice to user
-       */
-
-      if (gpu_temp_disable == 0)
-      {
-        const int gpu_temp_threshold_slowdown = hm_get_threshold_slowdown_with_device_id (device_id);
-
-        data.hm_device[device_id].gpu_temp_threshold_slowdown = (gpu_temp_threshold_slowdown == -1) ? 100000 : gpu_temp_threshold_slowdown;
-      }
-
       /**
        * Store initial fanspeed if gpu_temp_retain is enabled
        */
@@ -15633,13 +15721,11 @@ int main (int argc, char **argv)
 
               if (device_param->device_vendor_id == VENDOR_ID_AMD)
               {
-                rc = hm_set_fanspeed_with_device_id_amd (device_id, fanspeed, 1);
+                rc = hm_set_fanspeed_with_device_id_adl (device_id, fanspeed, 1);
               }
               else if (device_param->device_vendor_id == VENDOR_ID_NV)
               {
-                #ifdef _WIN
-                rc = hm_set_fanspeed_with_device_id_nvapi (device_id, fanspeed, 1);
-                #endif
+
               }
 
               if (rc == 0)
@@ -15663,127 +15749,9 @@ int main (int argc, char **argv)
         }
       }
 
-      /**
-       * Store original powercontrol/clocks settings, set overdrive 6 performance tuning settings
-       */
-
-      if (powertune_enable == 1) // VENDOR_ID_AMD implied
-      {
-        hc_thread_mutex_lock (mux_adl);
-
-        if (data.hm_device[device_id].od_version == 6)
-        {
-          int ADL_rc;
-
-          // check powertune capabilities first, if not available then skip device
-
-          int powertune_supported = 0;
-
-          if ((ADL_rc = hm_ADL_Overdrive6_PowerControl_Caps (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &powertune_supported)) != ADL_OK)
-          {
-            log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
-
-            return (-1);
-          }
-
-          if (powertune_supported != 0)
-          {
-            // powercontrol settings
-
-            ADLOD6PowerControlInfo powertune = {0, 0, 0, 0, 0};
-
-            if ((ADL_rc = hm_ADL_Overdrive_PowerControlInfo_Get (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &powertune)) == ADL_OK)
-            {
-              ADL_rc = hm_ADL_Overdrive_PowerControl_Get (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &od_power_control_status[device_id]);
-            }
-
-            if (ADL_rc != ADL_OK)
-            {
-              log_error ("ERROR: Failed to get current ADL PowerControl settings");
-
-              return (-1);
-            }
-
-            if ((ADL_rc = hm_ADL_Overdrive_PowerControl_Set (data.hm_amd, data.hm_device[device_id].adapter_index.amd, powertune.iMaxValue)) != ADL_OK)
-            {
-              log_error ("ERROR: Failed to set new ADL PowerControl values");
-
-              return (-1);
-            }
-
-            // clocks
-
-            memset (&od_clock_mem_status[device_id], 0, sizeof (ADLOD6MemClockState));
-
-            od_clock_mem_status[device_id].state.iNumberOfPerformanceLevels = 2;
-
-            if ((ADL_rc = hm_ADL_Overdrive_StateInfo_Get (data.hm_amd, data.hm_device[device_id].adapter_index.amd, ADL_OD6_GETSTATEINFO_CUSTOM_PERFORMANCE, &od_clock_mem_status[device_id])) != ADL_OK)
-            {
-              log_error ("ERROR: Failed to get ADL memory and engine clock frequency");
-
-              return (-1);
-            }
-
-            // Query capabilities only to see if profiles were not "damaged", if so output a warning but do accept the users profile settings
-
-            ADLOD6Capabilities caps = {0, 0, 0, {0, 0, 0}, {0, 0, 0}, 0, 0};
-
-            if ((ADL_rc = hm_ADL_Overdrive_Capabilities_Get (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &caps)) != ADL_OK)
-            {
-              log_error ("ERROR: Failed to get ADL device capabilities");
-
-              return (-1);
-            }
-
-            int engine_clock_max = caps.sEngineClockRange.iMax * 0.6666;
-            int memory_clock_max = caps.sMemoryClockRange.iMax * 0.6250;
-
-            int warning_trigger_engine = (int) (0.25 * (float) engine_clock_max);
-            int warning_trigger_memory = (int) (0.25 * (float) memory_clock_max);
-
-            int engine_clock_profile_max = od_clock_mem_status[device_id].state.aLevels[1].iEngineClock;
-            int memory_clock_profile_max = od_clock_mem_status[device_id].state.aLevels[1].iMemoryClock;
-
-            // warning if profile has too low max values
-
-            if ((engine_clock_max - engine_clock_profile_max) > warning_trigger_engine)
-            {
-              log_info ("WARN: the custom profile seems to have too low maximum engine clock values. You therefore may not reach full performance");
-            }
-
-            if ((memory_clock_max - memory_clock_profile_max) > warning_trigger_memory)
-            {
-              log_info ("WARN: the custom profile seems to have too low maximum memory clock values. You therefore may not reach full performance");
-            }
-
-            ADLOD6StateInfo *performance_state = (ADLOD6StateInfo*) mycalloc (1, sizeof (ADLOD6StateInfo) + sizeof (ADLOD6PerformanceLevel));
-
-            performance_state->iNumberOfPerformanceLevels = 2;
-
-            performance_state->aLevels[0].iEngineClock = engine_clock_profile_max;
-            performance_state->aLevels[1].iEngineClock = engine_clock_profile_max;
-            performance_state->aLevels[0].iMemoryClock = memory_clock_profile_max;
-            performance_state->aLevels[1].iMemoryClock = memory_clock_profile_max;
-
-            if ((ADL_rc = hm_ADL_Overdrive_State_Set (data.hm_amd, data.hm_device[device_id].adapter_index.amd, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
-            {
-              log_info ("ERROR: Failed to set ADL performance state");
-
-              return (-1);
-            }
-
-            local_free (performance_state);
-          }
-        }
-
-        hc_thread_mutex_unlock (mux_adl);
-      }
-
       #endif // HAVE_HWMON
     }
 
-    data.kernel_power_all = kernel_power_all;
-
     if (data.quiet == 0) log_info_nn ("");
 
     /**
@@ -17008,6 +16976,8 @@ int main (int argc, char **argv)
 
         data.ms_paused = 0;
 
+        data.kernel_power_div = 0;
+
         data.words_cur = rd->words_cur;
 
         for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
@@ -17025,8 +16995,6 @@ int main (int argc, char **argv)
 
           memset (device_param->exec_ms, 0, EXEC_CACHE * sizeof (double));
 
-          device_param->kernel_power = device_param->kernel_power_user;
-
           device_param->outerloop_pos  = 0;
           device_param->outerloop_left = 0;
           device_param->innerloop_pos  = 0;
@@ -17042,8 +17010,6 @@ int main (int argc, char **argv)
           device_param->words_done = 0;
         }
 
-        data.kernel_power_div = 0;
-
         // figure out some workload
 
         if (attack_mode == ATTACK_MODE_STRAIGHT)
@@ -17485,26 +17451,6 @@ int main (int argc, char **argv)
           }
         }
 
-        /*
-         * Inform user about possible slow speeds
-         */
-
-        if ((wordlist_mode == WL_MODE_FILE) || (wordlist_mode == WL_MODE_MASK))
-        {
-          if (data.words_base < kernel_power_all)
-          {
-            if (quiet == 0)
-            {
-              log_info ("ATTENTION!");
-              log_info ("  The wordlist or mask you are using is too small.");
-              log_info ("  Therefore, hashcat is unable to utilize the full parallelization power of your device(s).");
-              log_info ("  The cracking speed will drop.");
-              log_info ("  Workaround: https://hashcat.net/wiki/doku.php?id=frequently_asked_questions#how_to_create_more_work_for_full_speed");
-              log_info ("");
-            }
-          }
-        }
-
         /*
          * Update loopback file
          */
@@ -17565,17 +17511,61 @@ int main (int argc, char **argv)
           if (data.quiet == 0) log_info ("");
         }
 
-        time_t runtime_start;
+        /**
+         * create autotune threads
+         */
 
-        time (&runtime_start);
+        hc_thread_t *c_threads = (hc_thread_t *) mycalloc (data.devices_cnt, sizeof (hc_thread_t));
 
-        data.runtime_start = runtime_start;
+        for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
+        {
+          hc_device_param_t *device_param = &devices_param[device_id];
+
+          hc_thread_create (c_threads[device_id], thread_autotune, device_param);
+        }
+
+        hc_thread_wait (data.devices_cnt, c_threads);
+
+        /*
+         * Inform user about possible slow speeds
+         */
+
+        uint kernel_power_all = 0;
+
+        for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
+        {
+          hc_device_param_t *device_param = &devices_param[device_id];
+
+          kernel_power_all += device_param->kernel_power;
+        }
+
+        data.kernel_power_all = kernel_power_all;
+
+        if ((wordlist_mode == WL_MODE_FILE) || (wordlist_mode == WL_MODE_MASK))
+        {
+          if (data.words_base < kernel_power_all)
+          {
+            if (quiet == 0)
+            {
+              log_info ("ATTENTION!");
+              log_info ("  The wordlist or mask you are using is too small.");
+              log_info ("  Therefore, hashcat is unable to utilize the full parallelization power of your device(s).");
+              log_info ("  The cracking speed will drop.");
+              log_info ("  Workaround: https://hashcat.net/wiki/doku.php?id=frequently_asked_questions#how_to_create_more_work_for_full_speed");
+              log_info ("");
+            }
+          }
+        }
 
         /**
          * create cracker threads
          */
 
-        hc_thread_t *c_threads = (hc_thread_t *) mycalloc (data.devices_cnt, sizeof (hc_thread_t));
+        time_t runtime_start;
+
+        time (&runtime_start);
+
+        data.runtime_start = runtime_start;
 
         for (uint device_id = 0; device_id < data.devices_cnt; device_id++)
         {
@@ -17591,8 +17581,6 @@ int main (int argc, char **argv)
           }
         }
 
-        // wait for crack threads to exit
-
         hc_thread_wait (data.devices_cnt, c_threads);
 
         local_free (c_threads);
@@ -17913,13 +17901,11 @@ int main (int argc, char **argv)
 
               if (device_param->device_vendor_id == VENDOR_ID_AMD)
               {
-                rc = hm_set_fanspeed_with_device_id_amd (device_id, fanspeed, 0);
+                rc = hm_set_fanspeed_with_device_id_adl (device_id, fanspeed, 0);
               }
               else if (device_param->device_vendor_id == VENDOR_ID_NV)
               {
-                #ifdef _WIN
-                rc = hm_set_fanspeed_with_device_id_nvapi (device_id, fanspeed, 16);
-                #endif
+
               }
 
               if (rc == -1) log_info ("WARNING: Failed to restore default fan speed and policy for device #%", device_id + 1);
@@ -17943,49 +17929,62 @@ int main (int argc, char **argv)
 
         if (device_param->skipped) continue;
 
-        if (data.hm_device[device_id].od_version == 6)
+        if (data.devices_param[device_id].device_vendor_id == VENDOR_ID_AMD)
         {
-          // check powertune capabilities first, if not available then skip device
-
-          int powertune_supported = 0;
-
-          if ((hm_ADL_Overdrive6_PowerControl_Caps (data.hm_amd, data.hm_device[device_id].adapter_index.amd, &powertune_supported)) != ADL_OK)
+          if (data.hm_device[device_id].od_version == 6)
           {
-            log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
+            // check powertune capabilities first, if not available then skip device
 
-            return (-1);
-          }
+            int powertune_supported = 0;
 
-          if (powertune_supported != 0)
-          {
-            // powercontrol settings
-
-            if ((hm_ADL_Overdrive_PowerControl_Set (data.hm_amd, data.hm_device[device_id].adapter_index.amd, od_power_control_status[device_id])) != ADL_OK)
+            if ((hm_ADL_Overdrive6_PowerControl_Caps (data.hm_adl, data.hm_device[device_id].adl, &powertune_supported)) != ADL_OK)
             {
-              log_info ("ERROR: Failed to restore the ADL PowerControl values");
+              log_error ("ERROR: Failed to get ADL PowerControl Capabilities");
 
               return (-1);
             }
 
-            // clocks
+            if (powertune_supported != 0)
+            {
+              // powercontrol settings
 
-            ADLOD6StateInfo *performance_state = (ADLOD6StateInfo*) mycalloc (1, sizeof (ADLOD6StateInfo) + sizeof (ADLOD6PerformanceLevel));
+              if ((hm_ADL_Overdrive_PowerControl_Set (data.hm_adl, data.hm_device[device_id].adl, od_power_control_status[device_id])) != ADL_OK)
+              {
+                log_info ("ERROR: Failed to restore the ADL PowerControl values");
 
-            performance_state->iNumberOfPerformanceLevels = 2;
+                return (-1);
+              }
 
-            performance_state->aLevels[0].iEngineClock = od_clock_mem_status[device_id].state.aLevels[0].iEngineClock;
-            performance_state->aLevels[1].iEngineClock = od_clock_mem_status[device_id].state.aLevels[1].iEngineClock;
-            performance_state->aLevels[0].iMemoryClock = od_clock_mem_status[device_id].state.aLevels[0].iMemoryClock;
-            performance_state->aLevels[1].iMemoryClock = od_clock_mem_status[device_id].state.aLevels[1].iMemoryClock;
+              // clocks
 
-            if ((hm_ADL_Overdrive_State_Set (data.hm_amd, data.hm_device[device_id].adapter_index.amd, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
-            {
-              log_info ("ERROR: Failed to restore ADL performance state");
+              ADLOD6StateInfo *performance_state = (ADLOD6StateInfo*) mycalloc (1, sizeof (ADLOD6StateInfo) + sizeof (ADLOD6PerformanceLevel));
 
-              return (-1);
+              performance_state->iNumberOfPerformanceLevels = 2;
+
+              performance_state->aLevels[0].iEngineClock = od_clock_mem_status[device_id].state.aLevels[0].iEngineClock;
+              performance_state->aLevels[1].iEngineClock = od_clock_mem_status[device_id].state.aLevels[1].iEngineClock;
+              performance_state->aLevels[0].iMemoryClock = od_clock_mem_status[device_id].state.aLevels[0].iMemoryClock;
+              performance_state->aLevels[1].iMemoryClock = od_clock_mem_status[device_id].state.aLevels[1].iMemoryClock;
+
+              if ((hm_ADL_Overdrive_State_Set (data.hm_adl, data.hm_device[device_id].adl, ADL_OD6_SETSTATE_PERFORMANCE, performance_state)) != ADL_OK)
+              {
+                log_info ("ERROR: Failed to restore ADL performance state");
+
+                return (-1);
+              }
+
+              local_free (performance_state);
             }
+          }
+        }
 
-            local_free (performance_state);
+        if (data.devices_param[device_id].device_vendor_id == VENDOR_ID_NV)
+        {
+          unsigned int limit = nvml_power_limit[device_id];
+
+          if (limit > 0)
+          {
+            hm_NVML_nvmlDeviceSetPowerManagementLimit (data.hm_nvml, 0, data.hm_device[device_id].nvml, limit);
           }
         }
       }
@@ -17995,32 +17994,22 @@ int main (int argc, char **argv)
 
     if (gpu_temp_disable == 0)
     {
-      if (data.hm_nv)
+      if (data.hm_nvml)
       {
-        #if defined(LINUX)
+        hm_NVML_nvmlShutdown (data.hm_nvml);
 
-        hm_NVML_nvmlShutdown (data.hm_nv);
-
-        nvml_close (data.hm_nv);
-
-        #elif defined(WIN)
-
-        hm_NvAPI_Unload (data.hm_nv);
-
-        nvapi_close (data.hm_nv);
-
-        #endif
+        nvml_close (data.hm_nvml);
 
-        data.hm_nv = NULL;
+        data.hm_nvml = NULL;
       }
 
-      if (data.hm_amd)
+      if (data.hm_adl)
       {
-        hm_ADL_Main_Control_Destroy (data.hm_amd);
+        hm_ADL_Main_Control_Destroy (data.hm_adl);
 
-        adl_close (data.hm_amd);
+        adl_close (data.hm_adl);
 
-        data.hm_amd = NULL;
+        data.hm_adl = NULL;
       }
     }
     #endif // HAVE_HWMON
@@ -18066,6 +18055,7 @@ int main (int argc, char **argv)
     local_free (temp_retain_fanspeed_value);
     local_free (od_clock_mem_status);
     local_free (od_power_control_status);
+    local_free (nvml_power_limit);
     #endif
 
     global_free (devices_param);