diff options
| -rw-r--r-- | hardinfo/dt_util.c | 127 | ||||
| -rw-r--r-- | hardinfo/gpu_util.c | 5 | ||||
| -rw-r--r-- | includes/dt_util.h | 15 | ||||
| -rw-r--r-- | includes/gpu_util.h | 2 | ||||
| -rw-r--r-- | modules/devices/gpu.c | 35 | 
5 files changed, 176 insertions, 8 deletions
| diff --git a/hardinfo/dt_util.c b/hardinfo/dt_util.c index b7b6073f..49d08f8b 100644 --- a/hardinfo/dt_util.c +++ b/hardinfo/dt_util.c @@ -52,6 +52,7 @@ static struct {      /* operating-points-v2: */      /* https://www.kernel.org/doc/Documentation/devicetree/bindings/opp/opp.txt */ +    { "operating-points-v2", DTP_PH_REF_OPP2 },      { "opp-hz", DTP_UINT64 },      { "opp-microvolt", DTP_UINT },      { "opp-microvolt-L0", DTP_UINT }, /* opp-microvolt-<named>, but this kind of */ @@ -482,6 +483,21 @@ uint32_t dtr_get_prop_u32(dtr *s, dtr_obj *node, const char *name) {      return ret;  } +uint64_t dtr_get_prop_u64(dtr *s, dtr_obj *node, const char *name) { +    dtr_obj *prop; +    char *ptmp; +    uint64_t ret = 0; + +    ptmp = g_strdup_printf("%s/%s", (node == NULL) ? "" : node->path, name); +    prop = dtr_obj_read(s, ptmp); +    if (prop != NULL && prop->data != NULL) { +        ret = be64toh(*prop->data_int64); +        dtr_obj_free(prop); +    } +    g_free(ptmp); +    return ret; +} +  int dtr_guess_type(dtr_obj *obj) {      char *tmp, *dash;      int i = 0, anc = 0, might_be_str = 1; @@ -537,7 +553,7 @@ int dtr_guess_type(dtr_obj *obj) {      return DTP_UNK;  } -char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) { +char *dtr_elem_phref(dtr *s, dt_uint e, int show_path, const char *extra) {      const char *ph_path, *al_label;      char *ret = NULL;      ph_path = dtr_phandle_lookup(s, be32toh(e)); @@ -546,12 +562,12 @@ char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) {          al_label = dtr_symbol_lookup_by_path(s, ph_path);          if (al_label != NULL) {              if (show_path) -                ret = g_strdup_printf("&%s (%s)", al_label, ph_path); +                ret = g_strdup_printf("&%s (%s) %s", al_label, ph_path, extra ? extra : "");              else -                ret = g_strdup_printf("&%s", al_label); +                ret = g_strdup_printf("&%s %s", al_label, extra ? extra : "");          } else {              if (show_path) -                ret = g_strdup_printf("0x%x (%s)", be32toh(e), ph_path); +                ret = g_strdup_printf("0x%x (%s) %s", be32toh(e), ph_path, extra ? extra : "");          }      }      if (ret == NULL) @@ -559,6 +575,20 @@ char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) {      return ret;  } +char *dtr_elem_oppv2(dtr_obj* obj) { +    char opp_str[512] = ""; +    dtr_obj *parent = dtr_get_parent_obj(obj); +    if (parent) { +        dt_opp_range *opp = dtr_get_opp_range(obj->dt, parent->path); +        if (opp) { +            snprintf(opp_str, 511, "[%d - %d %s]", opp->khz_min, opp->khz_max, _("kHz")); +            free(opp); +        } +        dtr_obj_free(parent); +    } +    return dtr_elem_phref(obj->dt, *obj->data_int, 1, opp_str); +} +  char *dtr_elem_hex(dt_uint e) {      return g_strdup_printf("0x%x", be32toh(e) );  } @@ -643,7 +673,7 @@ char *dtr_list_override(dtr_obj *obj) {      int l, consumed = 0;      src = obj->data_str;      while (consumed + 5 <= obj->length) { -        ph = dtr_elem_phref(obj->dt, *(dt_uint*)src, 1); +        ph = dtr_elem_phref(obj->dt, *(dt_uint*)src, 1, NULL);          src += 4; consumed += 4;          l = strlen(src) + 1; /* consume the null */          str = dtr_list_str0(src, l); @@ -682,7 +712,7 @@ char *dtr_list_phref(dtr_obj *obj, char *ext_cell_prop) {              ext_cells = 0;          else              ext_cells = dtr_get_phref_prop(obj->dt, be32toh(obj->data_int[i]), ext_cell_prop); -        ph = dtr_elem_phref(obj->dt, obj->data_int[i], 0); i++; +        ph = dtr_elem_phref(obj->dt, obj->data_int[i], 0, NULL); i++;          if (ext_cells > count - i) ext_cells = count - i;          ext = dtr_list_hex((obj->data_int + i), ext_cells); i+=ext_cells;          ret = appf(ret, "<%s%s%s>", @@ -814,7 +844,10 @@ char* dtr_str(dtr_obj *obj) {                  ret = dtr_list_hex(obj->data, obj->length / 4);              break;          case DTP_PH_REF: -            ret = dtr_elem_phref(obj->dt, *obj->data_int, 1); +            ret = dtr_elem_phref(obj->dt, *obj->data_int, 1, NULL); +            break; +        case DTP_PH_REF_OPP2: +            ret = dtr_elem_oppv2(obj);              break;          case DTP_UINT:              ret = dtr_elem_uint(*obj->data_int); @@ -895,6 +928,86 @@ int dtr_inh_find(dtr_obj *obj, char *qprop, int limit) {      return ret;  } +dt_opp_range *dtr_get_opp_range(dtr *s, const char *name) { +    dt_opp_range *ret = NULL; +    dtr_obj *obj = NULL, *table_obj = NULL, *row_obj = NULL; +    uint32_t opp_ph = 0; +    const char *opp_table_path = NULL; +    char *tab_compat = NULL, *tab_status = NULL; +    const gchar *fn; +    gchar *full_path; +    GDir *dir; +    uint64_t khz = 0; +    uint32_t lns = 0; +    char *row_status = NULL; + +    if (!s) +        return NULL; + +    obj = dtr_obj_read(s, name); +    if (!obj) +        goto get_opp_finish; + +    opp_ph = dtr_get_prop_u32(s, obj, "operating-points-v2"); +    if (!opp_ph) +        goto get_opp_finish; + +    opp_table_path = dtr_phandle_lookup(s, opp_ph); +    if (!opp_table_path) +        goto get_opp_finish; + +    table_obj = dtr_obj_read(s, opp_table_path); +    if (!table_obj) +        goto get_opp_finish; + +    tab_compat = dtr_get_prop_str(s, table_obj, "compatible"); +    tab_status = dtr_get_prop_str(s, table_obj, "status"); + +    if (!tab_compat || strcmp(tab_compat, "operating-points-v2") != 0) +        goto get_opp_finish; +    if (tab_status && strcmp(tab_status, "disabled") == 0) +        goto get_opp_finish; + +    ret = malloc(sizeof(dt_opp_range)); +    ret->phandle = opp_ph; +    ret->khz_min = ret->khz_max = ret->clock_latency_ns = 0; + +    full_path = dtr_obj_full_path(table_obj); +    dir = g_dir_open(full_path, 0 , NULL); +    if (dir) { +        while((fn = g_dir_read_name(dir)) != NULL) { +            row_obj = dtr_get_prop_obj(s, table_obj, fn); +            if (row_obj->type == DT_NODE) { +                row_status = dtr_get_prop_str(s, row_obj, "status"); +                if (!row_status || strcmp(row_status, "disabled") != 0) { +                    khz = dtr_get_prop_u64(s, row_obj, "opp-hz"); +                    khz /= 1000; /* 64b hz -> 32b khz */ +                    lns = dtr_get_prop_u32(s, row_obj, "clock-latency-ns"); +                    if (khz > ret->khz_max) +                        ret->khz_max = khz; +                    if (khz < ret->khz_min || ret->khz_min == 0) +                        ret->khz_min = khz; +                    ret->clock_latency_ns = lns; +                } +            } +            free(row_status); row_status = NULL; +            dtr_obj_free(row_obj); +            row_obj = NULL; +        } +        g_dir_close(dir); +    } +    g_free(full_path); + +get_opp_finish: +    dtr_obj_free(obj); +    dtr_obj_free(table_obj); +    free(tab_status); +    free(tab_compat); +    free(row_status); +    return ret; +} + +  void _dtr_read_aliases(dtr *s) {      gchar *dir_path;      GDir *dir; diff --git a/hardinfo/gpu_util.c b/hardinfo/gpu_util.c index 4347aad6..dee3c431 100644 --- a/hardinfo/gpu_util.c +++ b/hardinfo/gpu_util.c @@ -97,6 +97,7 @@ void gpud_free(gpud *s) {          free(s->drm_dev);          free(s->sysfs_drm_path);          free(s->dt_compat); +        free(s->dt_opp);          pcid_free(s->pci_dev);          nvgpu_free(s->nv_info);          g_free(s); @@ -301,6 +302,10 @@ gpud *dt_soc_gpu() {      gpu->dt_status = dtr_get_string(tmp_path, 1);      snprintf(tmp_path, 255, "%s/name", dt_gpu_path);      gpu->dt_name = dtr_get_string(tmp_path, 1); +    gpu->dt_opp = dtr_get_opp_range(dt, dt_gpu_path); +    if (gpu->dt_opp) { +        gpu->khz_max = gpu->dt_opp->khz_max; +    }      EMPIFNULL(gpu->dt_name);      EMPIFNULL(gpu->dt_status); diff --git a/includes/dt_util.h b/includes/dt_util.h index 0fbd53cf..62b215fc 100644 --- a/includes/dt_util.h +++ b/includes/dt_util.h @@ -30,6 +30,7 @@ enum {      DTP_CLOCKS,  /* <phref, #clock-cells> */      DTP_GPIOS,   /* <phref, #gpio-cells> */      DTP_DMAS,    /* dma-specifier list */ +    DTP_PH_REF_OPP2,  /* phandle reference to opp-v2 table */  };  /* simplest, no aliases, doesn't require an existing dt. @@ -55,18 +56,20 @@ char *dtr_obj_alias(dtr_obj *);  char *dtr_obj_symbol(dtr_obj *);  char *dtr_obj_path(dtr_obj *);        /* device tree path */  char *dtr_obj_full_path(dtr_obj *);   /* system path */ +dtr_obj *dtr_get_parent_obj(dtr_obj *);  /* find property/node 'name' relative to node   * if node is NULL, then from root */  dtr_obj *dtr_get_prop_obj(dtr *, dtr_obj *node, const char *name);  char *dtr_get_prop_str(dtr *, dtr_obj *node, const char *name);  uint32_t dtr_get_prop_u32(dtr *, dtr_obj *node, const char *name); +uint64_t dtr_get_prop_u64(dtr *, dtr_obj *node, const char *name);  /* attempts to render the object as a string */  char* dtr_str(dtr_obj *obj);  int dtr_guess_type(dtr_obj *obj); -char *dtr_elem_phref(dtr *, dt_uint e, int show_path); +char *dtr_elem_phref(dtr *, dt_uint e, int show_path, const char *extra);  char *dtr_elem_hex(dt_uint e);  char *dtr_elem_byte(uint8_t e);  char *dtr_elem_uint(dt_uint e); @@ -88,4 +91,14 @@ void dtr_msg(dtr *s, char *fmt, ...);   * ex: ret = appf(ret, "%s=%s\n", name, value); */  char *appf(char *src, char *fmt, ...); +/* operating-points-v2 */ +typedef struct { +    uint32_t phandle; +    uint32_t khz_min; +    uint32_t khz_max; +    uint32_t clock_latency_ns; +} dt_opp_range; + +dt_opp_range *dtr_get_opp_range(dtr *, const char *name); +  #endif diff --git a/includes/gpu_util.h b/includes/gpu_util.h index 0523cc81..1eb3c6c4 100644 --- a/includes/gpu_util.h +++ b/includes/gpu_util.h @@ -35,6 +35,7 @@ typedef struct gpud {      char *vendor_str;      char *device_str;      char *location; +    uint32_t khz_max;      char *drm_dev;      char *sysfs_drm_path; @@ -42,6 +43,7 @@ typedef struct gpud {      char *dt_compat, *dt_status, *dt_name, *dt_path;      const char *dt_vendor, *dt_device; +    dt_opp_range *dt_opp;      nvgpu *nv_info;      /* ... */ diff --git a/modules/devices/gpu.c b/modules/devices/gpu.c index 429b0b0f..75776d7e 100644 --- a/modules/devices/gpu.c +++ b/modules/devices/gpu.c @@ -127,12 +127,19 @@ static void _gpu_pci_dev(gpud* gpu) {      } else          nv_str = strdup(""); +    gchar *freq = g_strdup(_("(Unknown)")); +    if (gpu->khz_max > 0) { +        freq = g_strdup_printf("%0.2f %s", (double) gpu->khz_max / 1000, _("MHz")); +    } +      str = g_strdup_printf("[%s]\n"               /* Location */  "%s=%s\n"               /* DRM Dev */   "%s=%s\n"               /* Class */     "%s=[%04x] %s\n"                               "%s"               /* Revision */  "%s=%02x\n" +                             "[%s]\n" +             /* Frequency */ "%s=%s\n"               /* NV */        "%s"               /* PCIe */      "%s"                               "[%s]\n" @@ -144,6 +151,8 @@ static void _gpu_pci_dev(gpud* gpu) {                  _("Class"), p->class, p->class_str,                  vendor_device_str,                  _("Revision"), p->revision, +                _("Clocks"), +                _("Core"), freq,                  nv_str,                  pcie_str,                  _("Driver"), @@ -169,10 +178,28 @@ int _dt_soc_gpu(gpud *gpu) {      gchar *device = gpu->device_str;      if (vendor == NULL) vendor = UNKSOC;      if (device == NULL) device = UNKSOC; +    gchar *freq = g_strdup(_("(Unknown)")); +    if (gpu->khz_max > 0) { +        freq = g_strdup_printf("%0.2f %s", (double) gpu->khz_max / 1000, _("MHz")); +    }      gchar *key = g_strdup(gpu->id);      gchar *name = (vendor == UNKSOC && device == UNKSOC)              ? g_strdup(_("Unknown integrated GPU"))              : g_strdup_printf("%s %s", vendor, device); + +    gchar *opp_str; +    if (gpu->dt_opp) { +        opp_str = g_strdup_printf("[%s]\n" +                     /* MinFreq */  "%s=%d %s\n" +                     /* MaxFreq */  "%s=%d %s\n" +                     /* Latency */  "%s=%d %s\n", +                    _("Frequency Scaling"), +                    _("Minimum"), gpu->dt_opp->khz_min, _("kHz"), +                    _("Maximum"), gpu->dt_opp->khz_max, _("kHz"), +                    _("Transition Latency"), gpu->dt_opp->clock_latency_ns, _("ns") ); +    } else +        opp_str = strdup(""); +      gpu_summary_add((gpu->nice_name) ? gpu->nice_name : name);      gpu_list = h_strdup_cprintf("$%s$%s=%s\n", gpu_list, key, key, name);      gchar *str = g_strdup_printf("[%s]\n" @@ -180,6 +207,9 @@ int _dt_soc_gpu(gpud *gpu) {               /* Vendor */  "%s=%s\n"               /* Device */  "%s=%s\n"                             "[%s]\n" +             /* Freq */    "%s=%s\n" +             /* opp-v2 */  "%s" +                           "[%s]\n"               /* Path */    "%s=%s\n"               /* Compat */  "%s=%s\n"               /* Status */  "%s=%s\n" @@ -188,6 +218,9 @@ int _dt_soc_gpu(gpud *gpu) {                  _("Location"), gpu->location,                  _("Vendor"), vendor,                  _("Device"), device, +                _("Clocks"), +                _("Core"), freq, +                opp_str,                  _("Device Tree Node"),                  _("Path"), gpu->dt_path,                  _("Compatible"), gpu->dt_compat, @@ -195,6 +228,8 @@ int _dt_soc_gpu(gpud *gpu) {                  _("Name"), gpu->dt_name                  );      moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */ +    g_free(freq); +    g_free(opp_str);      return 1;  } | 
