Path: blob/21.2-virgl/src/freedreno/perfcntrs/freedreno_dt.c
4565 views
/*1* Copyright © 2021 Google, Inc.2* All Rights Reserved.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR19* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21* OTHER DEALINGS IN THE SOFTWARE.22*/2324#include <fcntl.h>25#include <ftw.h>26#include <inttypes.h>27#include <stdint.h>28#include <stdio.h>29#include <stdlib.h>30#include <string.h>31#include <unistd.h>32#include <arpa/inet.h>33#include <sys/mman.h>34#include <sys/stat.h>35#include <sys/types.h>3637#include "util/macros.h"38#include "util/os_file.h"3940#include "freedreno_dt.h"4142static struct {43char *dtnode;44int address_cells, size_cells;45uint64_t base;46uint32_t size;47uint32_t min_freq;48uint32_t max_freq;49} dev;5051/*52* code to find stuff in /proc/device-tree:53*54* NOTE: if we sampled the counters from the cmdstream, we could avoid needing55* /dev/mem and /proc/device-tree crawling. OTOH when the GPU is heavily loaded56* we would be competing with whatever else is using the GPU.57*/5859static void *60readdt(const char *node)61{62char *path;63void *buf;64size_t sz;6566(void)asprintf(&path, "%s/%s", dev.dtnode, node);67buf = os_read_file(path, &sz);68free(path);6970return buf;71}7273static int74find_freqs_fn(const char *fpath, const struct stat *sb, int typeflag,75struct FTW *ftwbuf)76{77const char *fname = fpath + ftwbuf->base;78size_t sz;7980if (strcmp(fname, "qcom,gpu-freq") == 0) {81uint32_t *buf = (uint32_t *)os_read_file(fpath, &sz);82uint32_t freq = ntohl(buf[0]);83free(buf);84dev.max_freq = MAX2(dev.max_freq, freq);85dev.min_freq = MIN2(dev.min_freq, freq);86}8788return 0;89}9091static void92find_freqs(void)93{94char *path;9596dev.min_freq = ~0;97dev.max_freq = 0;9899(void)asprintf(&path, "%s/%s", dev.dtnode, "qcom,gpu-pwrlevels");100101nftw(path, find_freqs_fn, 64, 0);102103free(path);104}105106static const char *compatibles[] = {107"qcom,adreno-3xx",108"qcom,kgsl-3d0",109"amd,imageon",110"qcom,adreno",111};112113/**114* compatstrs is a list of compatible strings separated by null, ie.115*116* compatible = "qcom,adreno-630.2", "qcom,adreno";117*118* would result in "qcom,adreno-630.2\0qcom,adreno\0"119*/120static bool121match_compatible(char *compatstrs, int sz)122{123while (sz > 0) {124char *compatible = compatstrs;125126for (unsigned i = 0; i < ARRAY_SIZE(compatibles); i++) {127if (strcmp(compatible, compatibles[i]) == 0) {128return true;129}130}131132compatstrs += strlen(compatible) + 1;133sz -= strlen(compatible) + 1;134}135return false;136}137138static int139find_device_fn(const char *fpath, const struct stat *sb, int typeflag,140struct FTW *ftwbuf)141{142const char *fname = fpath + ftwbuf->base;143size_t sz;144145if (strcmp(fname, "compatible") == 0) {146char *str = os_read_file(fpath, &sz);147if (match_compatible(str, sz)) {148int dlen = strlen(fpath) - strlen("/compatible");149dev.dtnode = malloc(dlen + 1);150memcpy(dev.dtnode, fpath, dlen);151dev.dtnode[dlen] = '\0';152printf("found dt node: %s\n", dev.dtnode);153154char buf[dlen + sizeof("/../#address-cells") + 1];155size_t sz;156int *val;157158sprintf(buf, "%s/../#address-cells", dev.dtnode);159val = (int *)os_read_file(buf, &sz);160dev.address_cells = ntohl(*val);161free(val);162163sprintf(buf, "%s/../#size-cells", dev.dtnode);164val = (int *)os_read_file(buf, &sz);165dev.size_cells = ntohl(*val);166free(val);167168printf("#address-cells=%d, #size-cells=%d\n", dev.address_cells,169dev.size_cells);170}171free(str);172}173if (dev.dtnode) {174/* we found it! */175return 1;176}177return 0;178}179180static bool181find_device(void)182{183int ret;184uint32_t *buf, *b;185186if (dev.dtnode)187return true;188189ret = nftw("/proc/device-tree/", find_device_fn, 64, 0);190if (ret < 0)191return false;192193if (!dev.dtnode)194return false;195196b = buf = readdt("reg");197198if (dev.address_cells == 2) {199uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};200dev.base = (((uint64_t)u[0]) << 32) | u[1];201buf += 2;202} else {203dev.base = ntohl(buf[0]);204buf += 1;205}206207if (dev.size_cells == 2) {208uint32_t u[2] = {ntohl(buf[0]), ntohl(buf[1])};209dev.size = (((uint64_t)u[0]) << 32) | u[1];210buf += 2;211} else {212dev.size = ntohl(buf[0]);213buf += 1;214}215216free(b);217218printf("i/o region at %08" PRIx64 " (size: %x)\n", dev.base, dev.size);219220find_freqs();221222printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);223224return true;225}226227bool228fd_dt_find_freqs(uint32_t *min_freq, uint32_t *max_freq)229{230if (!find_device())231return false;232233*min_freq = dev.min_freq;234*max_freq = dev.max_freq;235236return true;237}238239void *240fd_dt_find_io(void)241{242if (!find_device())243return NULL;244245int fd = open("/dev/mem", O_RDWR | O_SYNC);246if (fd < 0)247return NULL;248249void *io =250mmap(0, dev.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev.base);251close(fd);252if (io == MAP_FAILED)253return NULL;254255return io;256}257258259