Imported Upstream version 1.2.0
[psensor-pkg-debian.git] / src / lib / amd.c
index ff60332..72a807e 100644 (file)
@@ -1,6 +1,8 @@
 /*
- * Copyright (C) 2010-2011 thgreasi@gmail.com
- * Copyright (C) 2010-2012 jeanfi@gmail.com
+ * Copyright (C) 2010-2011 thgreasi@gmail.com, jeanfi@gmail.com
+ * Copyright (C) 2012-2014 jeanfi@gmail.com
+ *
+ * GPU usage is a contribution of MestreLion
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #ifndef LINUX
 #define LINUX 1
 #endif
-#ifdef HAVE_LIBATIADL
-       /* AMD id for the aticonfig */
-       int amd_id;
-#endif
 
 #include <locale.h>
 #include <libintl.h>
 
 #include <adl_sdk.h>
 
-#include "psensor.h"
+#include <psensor.h>
 
 typedef int (*ADL_MAIN_CONTROL_CREATE)(ADL_MAIN_MALLOC_CALLBACK, int);
 typedef int (*ADL_MAIN_CONTROL_DESTROY)();
 typedef int (*ADL_ADAPTER_NUMBEROFADAPTERS_GET) (int *);
 typedef int (*ADL_ADAPTER_ADAPTERINFO_GET) (LPAdapterInfo, int);
 typedef int (*ADL_ADAPTER_ACTIVE_GET) (int, int*);
-typedef int (*ADL_OVERDRIVE5_TEMPERATURE_GET) (int, int, ADLTemperature*);
-typedef int (*ADL_OVERDRIVE5_FANSPEED_GET) (int, int, ADLFanSpeedValue*);
-
-static ADL_MAIN_CONTROL_CREATE            adl_main_control_create;
-static ADL_MAIN_CONTROL_DESTROY           adl_main_control_destroy;
-static ADL_ADAPTER_NUMBEROFADAPTERS_GET   adl_adapter_numberofadapters_get;
-static ADL_ADAPTER_ADAPTERINFO_GET        adl_adapter_adapterinfo_get;
-static ADL_ADAPTER_ACTIVE_GET             adl_adapter_active_get;
-static ADL_OVERDRIVE5_TEMPERATURE_GET     adl_overdrive5_temperature_get;
-static ADL_OVERDRIVE5_FANSPEED_GET        adl_overdrive5_fanspeed_get;
+typedef int (*ADL_OD5_TEMPERATURE_GET) (int, int, ADLTemperature*);
+typedef int (*ADL_OD5_FANSPEED_GET) (int, int, ADLFanSpeedValue*);
+typedef int (*ADL_OD5_CURRENTACTIVITY_GET) (int, ADLPMActivity*);
+
+static ADL_MAIN_CONTROL_CREATE adl_main_control_create;
+static ADL_MAIN_CONTROL_DESTROY adl_main_control_destroy;
+static ADL_ADAPTER_NUMBEROFADAPTERS_GET adl_adapter_numberofadapters_get;
+static ADL_ADAPTER_ADAPTERINFO_GET adl_adapter_adapterinfo_get;
+static ADL_ADAPTER_ACTIVE_GET adl_adapter_active_get;
+static ADL_OD5_TEMPERATURE_GET adl_od5_temperature_get;
+static ADL_OD5_FANSPEED_GET adl_od5_fanspeed_get;
+static ADL_OD5_CURRENTACTIVITY_GET adl_od5_currentactivity_get;
 
 static void *hdll;
 static int adl_main_control_done;
-static int *active_amd_adapters;
+static int *active_adapters;
 
-/* Memory allocation function */
 static void __stdcall *adl_main_memory_alloc(int isize)
 {
        void *lpbuffer = malloc(isize);
        return lpbuffer;
 }
 
-static void *getprocaddress(void *plibrary, const char * name)
+static void *getprocaddress(void *plibrary, const char *name)
 {
        return dlsym(plibrary, name);
 }
 
-/*
-  Returns the temperature (Celcius) of an AMD/Ati GPU.
-*/
+/* Returns the temperature (Celsius) of an AMD/ATI GPU. */
 static double get_temp(struct psensor *sensor)
 {
-       ADLTemperature temperature;
+       ADLTemperature v;
 
-       temperature.iSize = sizeof(ADLTemperature);
-       temperature.iTemperature = -273;
-       if (ADL_OK != adl_overdrive5_temperature_get(sensor->amd_id,
-                0, &temperature))
-               return UNKNOWN_DBL_VALUE;
+       v.iSize = sizeof(ADLTemperature);
+       v.iTemperature = -273;
 
-       return temperature.iTemperature/1000;
+       if (adl_od5_temperature_get(sensor->amd_id, 0, &v) == ADL_OK)
+               return v.iTemperature/1000;
+
+       return UNKNOWN_DBL_VALUE;
 }
 
 static double get_fanspeed(struct psensor *sensor)
 {
-       ADLFanSpeedValue fanspeedvalue;
+       ADLFanSpeedValue v;
+
+       v.iSize = sizeof(ADLFanSpeedValue);
+       v.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
+       v.iFanSpeed = -1;
 
-       fanspeedvalue.iSize = sizeof(ADLFanSpeedValue);
-       fanspeedvalue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
-       fanspeedvalue.iFanSpeed = -1;
-       if (ADL_OK != adl_overdrive5_fanspeed_get(sensor->amd_id,
-                0, &fanspeedvalue))
-               return UNKNOWN_DBL_VALUE;
+       if (adl_od5_fanspeed_get(sensor->amd_id, 0, &v) == ADL_OK)
+               return v.iFanSpeed;
 
-       return fanspeedvalue.iFanSpeed;
+       return UNKNOWN_DBL_VALUE;
 }
 
-static struct psensor *create_sensor(int id, int values_len)
+static double get_usage(struct psensor *sensor)
+{
+       ADLPMActivity v;
+
+       v.iSize = sizeof(ADLPMActivity);
+
+       if (adl_od5_currentactivity_get(sensor->amd_id, &v) == ADL_OK)
+               return v.iActivityPercent;
+
+       return UNKNOWN_DBL_VALUE;
+}
+
+static struct psensor *create_sensor(int id, int type, int values_len)
 {
        char name[200];
        char *sid;
        int sensor_type;
-
        struct psensor *s;
 
-       if (id & 1) {/* odd number ids represent fan sensors */
-               id = id >> 1;
-               sprintf(name, "GPU%dfan", id);
-               sensor_type = SENSOR_TYPE_AMD_FAN;
-       } else {/* even number ids represent temperature sensors */
-               id = id >> 1;
-               sprintf(name, "GPU%dtemp", id);
-               sensor_type = SENSOR_TYPE_AMD_TEMP;
+       sensor_type = SENSOR_TYPE_ATIADL;
+       switch (type) {
+       /* Fan rotation speed */
+       case 0:
+               sprintf(name, "AMD GPU%d Fan", id);
+               sensor_type |= SENSOR_TYPE_FAN | SENSOR_TYPE_RPM;
+               break;
+
+       /* Temperature */
+       case 1:
+               sprintf(name, "AMD GPU%d Temperature", id);
+               sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_TEMP;
+               break;
+
+       /* GPU Usage (Activity/Load %) */
+       case 2:
+               sprintf(name, "AMD GPU%d Usage", id);
+               sensor_type |= SENSOR_TYPE_GPU | SENSOR_TYPE_PERCENT;
+               break;
        }
 
        sid = malloc(strlen("amd") + 1 + strlen(name) + 1);
        sprintf(sid, "amd %s", name);
 
-       s = psensor_create(sid, strdup(name),
-                          sensor_type, values_len);
+       s = psensor_create(sid,
+                          strdup(name),
+                          strdup("AMD/ATI GPU"),
+                          sensor_type,
+                          values_len);
 
-       s->amd_id = active_amd_adapters[id];
+       s->amd_id = active_adapters[id];
 
        return s;
 }
 
 /*
-  Returns the number of AMD/Ati GPU sensors (temperature and fan
-  speed).
-
-  Return 0 if no AMD/Ati gpus or cannot get information.
-*/
-static int init()
+ * Returns the number of active AMD/ATI GPU adapters
+ *
+ * Return 0 if no AMD/ATI GPUs or cannot get information.
+ */
+static int init(void)
 {
-       LPAdapterInfo lpadapterinfo = NULL;
-       int i, inumberadapters, inumberadaptersactive = 0;
-       int lpstatus, iadapterindex;
+       LPAdapterInfo lpadapterinfo;
+       int i, inumberadapters, inumberadaptersactive, lpstatus, iadapterindex;
 
-       hdll = NULL;
        adl_main_control_done = 0;
-       active_amd_adapters = NULL;
-       hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
+       inumberadaptersactive = 0;
+       active_adapters = NULL;
+       lpadapterinfo = NULL;
 
+       hdll = dlopen("libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
        if (!hdll) {
-               fprintf(stderr,
-                       _("ERROR: ADL library not found!\n"));
+               log_debug(_("AMD: cannot found ADL library."));
                return 0;
        }
 
        adl_main_control_create = (ADL_MAIN_CONTROL_CREATE)
-                getprocaddress(hdll, "ADL_Main_Control_Create");
+               getprocaddress(hdll, "ADL_Main_Control_Create");
        adl_main_control_destroy = (ADL_MAIN_CONTROL_DESTROY)
-                getprocaddress(hdll, "ADL_Main_Control_Destroy");
+               getprocaddress(hdll, "ADL_Main_Control_Destroy");
        adl_adapter_numberofadapters_get = (ADL_ADAPTER_NUMBEROFADAPTERS_GET)
-                getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
+               getprocaddress(hdll, "ADL_Adapter_NumberOfAdapters_Get");
        adl_adapter_adapterinfo_get = (ADL_ADAPTER_ADAPTERINFO_GET)
-                getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
+               getprocaddress(hdll, "ADL_Adapter_AdapterInfo_Get");
        adl_adapter_active_get = (ADL_ADAPTER_ACTIVE_GET)
-                getprocaddress(hdll, "ADL_Adapter_Active_Get");
-       adl_overdrive5_temperature_get = (ADL_OVERDRIVE5_TEMPERATURE_GET)
-                getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
-       adl_overdrive5_fanspeed_get = (ADL_OVERDRIVE5_FANSPEED_GET)
-                getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
-       if (!adl_main_control_create ||
-               !adl_main_control_destroy ||
-               !adl_adapter_numberofadapters_get ||
-               !adl_adapter_adapterinfo_get ||
-               !adl_overdrive5_temperature_get ||
-               !adl_overdrive5_fanspeed_get) {
-               fprintf(stderr,
-                       _("ERROR: ADL's API is missing!\n"));
+               getprocaddress(hdll, "ADL_Adapter_Active_Get");
+       adl_od5_temperature_get = (ADL_OD5_TEMPERATURE_GET)
+               getprocaddress(hdll, "ADL_Overdrive5_Temperature_Get");
+       adl_od5_fanspeed_get = (ADL_OD5_FANSPEED_GET)
+               getprocaddress(hdll, "ADL_Overdrive5_FanSpeed_Get");
+       adl_od5_currentactivity_get = (ADL_OD5_CURRENTACTIVITY_GET)
+               getprocaddress(hdll, "ADL_Overdrive5_CurrentActivity_Get");
+       if (!adl_main_control_create
+           || !adl_main_control_destroy
+           || !adl_adapter_numberofadapters_get
+           || !adl_adapter_adapterinfo_get
+           || !adl_od5_temperature_get
+           || !adl_od5_fanspeed_get
+           || !adl_od5_currentactivity_get) {
+               log_err(_("AMD: missing ADL's API."));
                return 0;
        }
 
-       /* Initialize ADL. The second parameter is 1, which means:
-          retrieve adapter information only for adapters that
-          are physically present and enabled in the system */
-       if (ADL_OK != adl_main_control_create(adl_main_memory_alloc, 1)) {
-               fprintf(stderr,
-                       _("ERROR: ADL Initialization Error!\n"));
+       /*
+        * 1 in 2nd parameter means retrieve adapter information only
+        * for adapters that are physically present and enabled in the
+        * system
+        */
+       if (adl_main_control_create(adl_main_memory_alloc, 1) != ADL_OK) {
+               log_err(_("AMD: failed to initialize ADL."));
                return 0;
        }
        adl_main_control_done = 1;
 
-       /* Obtain the number of adapters for the system */
-       if (ADL_OK != adl_adapter_numberofadapters_get(&inumberadapters)) {
-               fprintf(stderr,
-                       _("ERROR: Cannot get the number of adapters!\n"));
+       if (adl_adapter_numberofadapters_get(&inumberadapters) != ADL_OK) {
+               log_err(_("AMD: cannot get the number of adapters."));
                return 0;
        }
 
@@ -200,40 +221,43 @@ static int init()
        lpadapterinfo = malloc(sizeof(AdapterInfo) * inumberadapters);
        memset(lpadapterinfo, '\0', sizeof(AdapterInfo) * inumberadapters);
 
-       /* Get the AdapterInfo structure for all adapters in the system */
        adl_adapter_adapterinfo_get(lpadapterinfo,
                                    sizeof(AdapterInfo) * inumberadapters);
 
-       /* Repeat for all available adapters in the system */
        for (i = 0; i < inumberadapters; i++) {
 
                iadapterindex = lpadapterinfo[i].iAdapterIndex;
 
-               if (ADL_OK != adl_adapter_active_get(iadapterindex, &lpstatus))
+               if (adl_adapter_active_get(iadapterindex, &lpstatus) != ADL_OK)
                        continue;
                if (lpstatus != ADL_TRUE)
-                       /* count only if the adapter is active */
                        continue;
 
-               if (!active_amd_adapters) {
-                       active_amd_adapters = (int *) malloc(sizeof(int));
+               if (!active_adapters) {
+                       active_adapters = (int *) malloc(sizeof(int));
                        inumberadaptersactive = 1;
                } else {
                        ++inumberadaptersactive;
-                       active_amd_adapters = (int *)realloc
-                               (active_amd_adapters,
+                       active_adapters = (int *)realloc
+                               (active_adapters,
                                 sizeof(int)*inumberadaptersactive);
+
+                       if (!active_adapters)
+                               exit(EXIT_FAILURE);
                }
-               active_amd_adapters[inumberadaptersactive-1] = iadapterindex;
+               active_adapters[inumberadaptersactive-1] = iadapterindex;
        }
 
        free(lpadapterinfo);
 
-       /* Each Adapter has one GPU temperature sensor and one fan
-          control sensor */
-       return 2*inumberadaptersactive;
+       log_debug(_("Number of AMD/ATI adapters: %d"), inumberadapters);
+       log_debug(_("Number of active AMD/ATI adapters: %d"),
+                 inumberadaptersactive);
+
+       return inumberadaptersactive;
 }
 
+/* Called regularly to update sensors values */
 void amd_psensor_list_update(struct psensor **sensors)
 {
        struct psensor **ss, *s;
@@ -242,39 +266,36 @@ void amd_psensor_list_update(struct psensor **sensors)
        while (*ss) {
                s = *ss;
 
-               if (s->type == SENSOR_TYPE_AMD_TEMP)
-                       psensor_set_current_value(s, get_temp(s));
-               else if (s->type == SENSOR_TYPE_AMD_FAN)
-                       psensor_set_current_value(s, get_fanspeed(s));
+               if (s->type & SENSOR_TYPE_ATIADL) {
+                       if (s->type & SENSOR_TYPE_TEMP)
+                               psensor_set_current_value(s, get_temp(s));
+                       else if (s->type & SENSOR_TYPE_RPM)
+                               psensor_set_current_value(s, get_fanspeed(s));
+                       else if (s->type & SENSOR_TYPE_PERCENT)
+                               psensor_set_current_value(s, get_usage(s));
+               }
 
                ss++;
        }
 }
 
-struct psensor * *
-amd_psensor_list_add(struct psensor **sensors, int values_len)
+/* Entry point for AMD sensors */
+void amd_psensor_list_append(struct psensor ***sensors, int values_len)
 {
-       int i, n;
-       struct psensor **tmp, **ss, *s;
+       int i, j, n;
+       struct psensor *s;
 
        n = init();
 
-       ss = sensors;
-       for (i = 0; i < n; i++) {
-               s = create_sensor(i, values_len);
-
-               tmp = psensor_list_add(ss, s);
-
-               if (ss != tmp)
-                       free(ss);
-
-               ss = tmp;
-       }
-
-       return ss;
+       for (i = 0; i < n; i++)
+               /* Each GPU Adapter has 3 sensors: temp, fan speed and usage */
+               for (j = 0; j < 3; j++) {
+                       s = create_sensor(i, j, values_len);
+                       psensor_list_append(sensors, s);
+               }
 }
 
-void amd_cleanup()
+void amd_cleanup(void)
 {
        if (hdll) {
                if (adl_main_control_done)
@@ -282,8 +303,8 @@ void amd_cleanup()
                dlclose(hdll);
        }
 
-       if (active_amd_adapters) {
-               free(active_amd_adapters);
-               active_amd_adapters = NULL;
+       if (active_adapters) {
+               free(active_adapters);
+               active_adapters = NULL;
        }
 }