Home | History | Annotate | Line # | Download | only in perfcntrs
      1 /*
      2  * Copyright  2021 Google, Inc.
      3  * All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #include <fcntl.h>
     26 #include <ftw.h>
     27 #include <inttypes.h>
     28 #include <stdint.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <unistd.h>
     33 #include <arpa/inet.h>
     34 #include <sys/mman.h>
     35 #include <sys/stat.h>
     36 #include <sys/types.h>
     37 
     38 #include "util/macros.h"
     39 #include "util/os_file.h"
     40 
     41 #include "freedreno_dt.h"
     42 
     43 static struct {
     44    char *dtnode;
     45    int address_cells, size_cells;
     46    uint64_t base;
     47    uint32_t size;
     48    uint32_t min_freq;
     49    uint32_t max_freq;
     50 } dev;
     51 
     52 /*
     53  * code to find stuff in /proc/device-tree:
     54  *
     55  * NOTE: if we sampled the counters from the cmdstream, we could avoid needing
     56  * /dev/mem and /proc/device-tree crawling.  OTOH when the GPU is heavily loaded
     57  * we would be competing with whatever else is using the GPU.
     58  */
     59 
     60 static void *
     61 readdt(const char *node)
     62 {
     63    char *path;
     64    void *buf;
     65    size_t sz;
     66 
     67    (void)asprintf(&path, "%s/%s", dev.dtnode, node);
     68    buf = os_read_file(path, &sz);
     69    free(path);
     70 
     71    return buf;
     72 }
     73 
     74 static int
     75 find_freqs_fn(const char *fpath, const struct stat *sb, int typeflag,
     76               struct FTW *ftwbuf)
     77 {
     78    const char *fname = fpath + ftwbuf->base;
     79    size_t sz;
     80 
     81    if (strcmp(fname, "qcom,gpu-freq") == 0) {
     82       uint32_t *buf = (uint32_t *)os_read_file(fpath, &sz);
     83       uint32_t freq = ntohl(buf[0]);
     84       free(buf);
     85       dev.max_freq = MAX2(dev.max_freq, freq);
     86       dev.min_freq = MIN2(dev.min_freq, freq);
     87    }
     88 
     89    return 0;
     90 }
     91 
     92 static void
     93 find_freqs(void)
     94 {
     95    char *path;
     96 
     97    dev.min_freq = ~0;
     98    dev.max_freq = 0;
     99 
    100    (void)asprintf(&path, "%s/%s", dev.dtnode, "qcom,gpu-pwrlevels");
    101 
    102    nftw(path, find_freqs_fn, 64, 0);
    103 
    104    free(path);
    105 }
    106 
    107 static const char *compatibles[] = {
    108    "qcom,adreno-3xx",
    109    "qcom,kgsl-3d0",
    110    "amd,imageon",
    111    "qcom,adreno",
    112 };
    113 
    114 /**
    115  * compatstrs is a list of compatible strings separated by null, ie.
    116  *
    117  *       compatible = "qcom,adreno-630.2", "qcom,adreno";
    118  *
    119  * would result in "qcom,adreno-630.2\0qcom,adreno\0"
    120  */
    121 static bool
    122 match_compatible(char *compatstrs, int sz)
    123 {
    124    while (sz > 0) {
    125       char *compatible = compatstrs;
    126 
    127       for (unsigned i = 0; i < ARRAY_SIZE(compatibles); i++) {
    128          if (strcmp(compatible, compatibles[i]) == 0) {
    129             return true;
    130          }
    131       }
    132 
    133       compatstrs += strlen(compatible) + 1;
    134       sz -= strlen(compatible) + 1;
    135    }
    136    return false;
    137 }
    138 
    139 static int
    140 find_device_fn(const char *fpath, const struct stat *sb, int typeflag,
    141                struct FTW *ftwbuf)
    142 {
    143    const char *fname = fpath + ftwbuf->base;
    144    size_t sz;
    145 
    146    if (strcmp(fname, "compatible") == 0) {
    147       char *str = os_read_file(fpath, &sz);
    148       if (match_compatible(str, sz)) {
    149          int dlen = strlen(fpath) - strlen("/compatible");
    150          dev.dtnode = malloc(dlen + 1);
    151          memcpy(dev.dtnode, fpath, dlen);
    152          dev.dtnode[dlen] = '\0';
    153          printf("found dt node: %s\n", dev.dtnode);
    154 
    155          char buf[dlen + sizeof("/../#address-cells") + 1];
    156          size_t sz;
    157          int *val;
    158 
    159          sprintf(buf, "%s/../#address-cells", dev.dtnode);
    160          val = (int *)os_read_file(buf, &sz);
    161          dev.address_cells = ntohl(*val);
    162          free(val);
    163 
    164          sprintf(buf, "%s/../#size-cells", dev.dtnode);
    165          val = (int *)os_read_file(buf, &sz);
    166          dev.size_cells = ntohl(*val);
    167          free(val);
    168 
    169          printf("#address-cells=%d, #size-cells=%d\n", dev.address_cells,
    170                 dev.size_cells);
    171       }
    172       free(str);
    173    }
    174    if (dev.dtnode) {
    175       /* we found it! */
    176       return 1;
    177    }
    178    return 0;
    179 }
    180 
    181 static bool
    182 find_device(void)
    183 {
    184    int ret;
    185    uint32_t *buf, *b;
    186 
    187    if (dev.dtnode)
    188       return true;
    189 
    190    ret = nftw("/proc/device-tree/", find_device_fn, 64, 0);
    191    if (ret < 0)
    192       return false;
    193 
    194    if (!dev.dtnode)
    195       return false;
    196 
    197    b = buf = readdt("reg");
    198 
    199    if (dev.address_cells == 2) {
    200       uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};
    201       dev.base = (((uint64_t)u[0]) << 32) | u[1];
    202       buf += 2;
    203    } else {
    204       dev.base = ntohl(buf[0]);
    205       buf += 1;
    206    }
    207 
    208    if (dev.size_cells == 2) {
    209       uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};
    210       dev.size = (((uint64_t)u[0]) << 32) | u[1];
    211       buf += 2;
    212    } else {
    213       dev.size = ntohl(buf[0]);
    214       buf += 1;
    215    }
    216 
    217    free(b);
    218 
    219    printf("i/o region at %08" PRIx64 " (size: %x)\n", dev.base, dev.size);
    220 
    221    find_freqs();
    222 
    223    printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);
    224 
    225    return true;
    226 }
    227 
    228 bool
    229 fd_dt_find_freqs(uint32_t *min_freq, uint32_t *max_freq)
    230 {
    231    if (!find_device())
    232       return false;
    233 
    234    *min_freq = dev.min_freq;
    235    *max_freq = dev.max_freq;
    236 
    237    return true;
    238 }
    239 
    240 void *
    241 fd_dt_find_io(void)
    242 {
    243    if (!find_device())
    244       return NULL;
    245 
    246    int fd = open("/dev/mem", O_RDWR | O_SYNC);
    247    if (fd < 0)
    248       return NULL;
    249 
    250    void *io =
    251       mmap(0, dev.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev.base);
    252    close(fd);
    253    if (io == MAP_FAILED)
    254       return NULL;
    255 
    256    return io;
    257 }
    258