msm_gpu_devfreq.o \
msm_io_utils.o \
msm_iommu.o \
- msm_perf.o \
msm_rd.o \
msm_ringbuffer.o \
msm_submitqueue.o \
return ring->memptrs->rptr;
}
-static const struct msm_gpu_perfcntr perfcntrs[] = {
-/* TODO */
-};
-
static struct msm_gpu *a2xx_gpu_init(struct drm_device *dev)
{
struct a2xx_gpu *a2xx_gpu = NULL;
adreno_gpu = &a2xx_gpu->base;
gpu = &adreno_gpu->base;
- gpu->perfcntrs = perfcntrs;
- gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
-
ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, 1);
if (ret)
goto fail;
/* Turn on performance counters: */
gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
- /* Enable the perfcntrs that we use.. */
- for (i = 0; i < gpu->num_perfcntrs; i++) {
- const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
- gpu_write(gpu, perfcntr->select_reg, perfcntr->select_val);
- }
-
gpu_write(gpu, REG_A3XX_RBBM_INT_0_MASK, A3XX_INT0_MASK);
ret = adreno_hw_init(gpu);
return ring->memptrs->rptr;
}
-static const struct msm_gpu_perfcntr perfcntrs[] = {
- { REG_A3XX_SP_PERFCOUNTER6_SELECT, REG_A3XX_RBBM_PERFCTR_SP_6_LO,
- SP_ALU_ACTIVE_CYCLES, "ALUACTIVE" },
- { REG_A3XX_SP_PERFCOUNTER7_SELECT, REG_A3XX_RBBM_PERFCTR_SP_7_LO,
- SP_FS_FULL_ALU_INSTRUCTIONS, "ALUFULL" },
-};
-
static struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
{
struct a3xx_gpu *a3xx_gpu = NULL;
adreno_gpu = &a3xx_gpu->base;
gpu = &adreno_gpu->base;
- gpu->perfcntrs = perfcntrs;
- gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
-
adreno_gpu->registers = a3xx_registers;
ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, 1);
adreno_gpu = &a4xx_gpu->base;
gpu = &adreno_gpu->base;
- gpu->perfcntrs = NULL;
- gpu->num_perfcntrs = 0;
-
ret = adreno_gpu_init(dev, pdev, adreno_gpu, config->info->funcs, 1);
if (ret)
goto fail;
return ret;
}
- ret = msm_perf_debugfs_init(minor);
- if (ret) {
- DRM_DEV_ERROR(dev->dev, "could not install perf debugfs\n");
- return ret;
- }
-
return 0;
}
msm_gem_shrinker_cleanup(ddev);
- msm_perf_debugfs_cleanup(priv);
msm_rd_debugfs_cleanup(priv);
if (priv->kms)
struct msm_mmu;
struct msm_mdss;
struct msm_rd_state;
-struct msm_perf_state;
struct msm_gem_submit;
struct msm_fence_context;
struct msm_disp_state;
struct msm_rd_state *rd; /* debugfs to dump all submits */
struct msm_rd_state *hangrd; /* debugfs to dump hanging submits */
- struct msm_perf_state *perf;
/**
* total_mem: Total/global amount of memory backing GEM objects.
__printf(3, 4)
void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
const char *fmt, ...);
-int msm_perf_debugfs_init(struct drm_minor *minor);
-void msm_perf_debugfs_cleanup(struct msm_drm_private *priv);
#else
static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; }
__printf(3, 4)
struct msm_gem_submit *submit,
const char *fmt, ...) {}
static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {}
-static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {}
#endif
struct clk *msm_clk_get(struct platform_device *pdev, const char *name);
msm_gpu_retire(gpu);
}
-/*
- * Performance Counters:
- */
-
-/* called under perf_lock */
-static int update_hw_cntrs(struct msm_gpu *gpu, uint32_t ncntrs, uint32_t *cntrs)
-{
- uint32_t current_cntrs[ARRAY_SIZE(gpu->last_cntrs)];
- int i, n = min(ncntrs, gpu->num_perfcntrs);
-
- /* read current values: */
- for (i = 0; i < gpu->num_perfcntrs; i++)
- current_cntrs[i] = gpu_read(gpu, gpu->perfcntrs[i].sample_reg);
-
- /* update cntrs: */
- for (i = 0; i < n; i++)
- cntrs[i] = current_cntrs[i] - gpu->last_cntrs[i];
-
- /* save current values: */
- for (i = 0; i < gpu->num_perfcntrs; i++)
- gpu->last_cntrs[i] = current_cntrs[i];
-
- return n;
-}
-
-static void update_sw_cntrs(struct msm_gpu *gpu)
-{
- ktime_t time;
- uint32_t elapsed;
- unsigned long flags;
-
- spin_lock_irqsave(&gpu->perf_lock, flags);
- if (!gpu->perfcntr_active)
- goto out;
-
- time = ktime_get();
- elapsed = ktime_to_us(ktime_sub(time, gpu->last_sample.time));
-
- gpu->totaltime += elapsed;
- if (gpu->last_sample.active)
- gpu->activetime += elapsed;
-
- gpu->last_sample.active = msm_gpu_active(gpu);
- gpu->last_sample.time = time;
-
-out:
- spin_unlock_irqrestore(&gpu->perf_lock, flags);
-}
-
-void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
-{
- unsigned long flags;
-
- pm_runtime_get_sync(&gpu->pdev->dev);
-
- spin_lock_irqsave(&gpu->perf_lock, flags);
- /* we could dynamically enable/disable perfcntr registers too.. */
- gpu->last_sample.active = msm_gpu_active(gpu);
- gpu->last_sample.time = ktime_get();
- gpu->activetime = gpu->totaltime = 0;
- gpu->perfcntr_active = true;
- update_hw_cntrs(gpu, 0, NULL);
- spin_unlock_irqrestore(&gpu->perf_lock, flags);
-}
-
-void msm_gpu_perfcntr_stop(struct msm_gpu *gpu)
-{
- gpu->perfcntr_active = false;
- pm_runtime_put_sync(&gpu->pdev->dev);
-}
-
-/* returns -errno or # of cntrs sampled */
-int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
- uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs)
-{
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&gpu->perf_lock, flags);
-
- if (!gpu->perfcntr_active) {
- ret = -EINVAL;
- goto out;
- }
-
- *activetime = gpu->activetime;
- *totaltime = gpu->totaltime;
-
- gpu->activetime = gpu->totaltime = 0;
-
- ret = update_hw_cntrs(gpu, ncntrs, cntrs);
-
-out:
- spin_unlock_irqrestore(&gpu->perf_lock, flags);
-
- return ret;
-}
-
/*
* Cmdstream submission/retirement:
*/
msm_update_fence(gpu->rb[i]->fctx, gpu->rb[i]->memptrs->fence);
kthread_queue_work(gpu->worker, &gpu->retire_work);
- update_sw_cntrs(gpu);
}
/* add bo's to gpu's ring, and kick gpu: */
submit->seqno = submit->hw_fence->seqno;
- update_sw_cntrs(gpu);
-
/*
* ring->submits holds a ref to the submit, to deal with the case
* that a submit completes before msm_ioctl_gem_submit() returns.
void *memptrs;
uint64_t memptrs_iova;
- if (WARN_ON(gpu->num_perfcntrs > ARRAY_SIZE(gpu->last_cntrs)))
- gpu->num_perfcntrs = ARRAY_SIZE(gpu->last_cntrs);
-
gpu->dev = drm;
gpu->funcs = funcs;
gpu->name = name;
timer_setup(&gpu->hangcheck_timer, hangcheck_handler, 0);
- spin_lock_init(&gpu->perf_lock);
-
-
/* Map registers: */
gpu->mmio = msm_ioremap(pdev, config->ioname);
if (IS_ERR(gpu->mmio)) {
struct msm_gem_submit;
struct msm_gem_vm_log_entry;
-struct msm_gpu_perfcntr;
struct msm_gpu_state;
struct msm_context;
struct adreno_smmu_priv adreno_smmu;
- /* performance counters (hw & sw): */
- spinlock_t perf_lock;
- bool perfcntr_active;
- struct {
- bool active;
- ktime_t time;
- } last_sample;
- uint32_t totaltime, activetime; /* sw counters */
- uint32_t last_cntrs[5]; /* hw counters */
- const struct msm_gpu_perfcntr *perfcntrs;
- uint32_t num_perfcntrs;
-
struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS];
int nr_rings;
return false;
}
-/* Perf-Counters:
- * The select_reg and select_val are just there for the benefit of the child
- * class that actually enables the perf counter.. but msm_gpu base class
- * will handle sampling/displaying the counters.
- */
-
-struct msm_gpu_perfcntr {
- uint32_t select_reg;
- uint32_t sample_reg;
- uint32_t select_val;
- const char *name;
-};
-
/*
* The number of priority levels provided by drm gpu scheduler. The
* DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some
int msm_gpu_hw_init(struct msm_gpu *gpu);
-void msm_gpu_perfcntr_start(struct msm_gpu *gpu);
-void msm_gpu_perfcntr_stop(struct msm_gpu *gpu);
-int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
- uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs);
-
void msm_gpu_retire(struct msm_gpu *gpu);
void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit);
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) 2013 Red Hat
- * Author: Rob Clark <robdclark@gmail.com>
- */
-
-/* For profiling, userspace can:
- *
- * tail -f /sys/kernel/debug/dri/<minor>/gpu
- *
- * This will enable performance counters/profiling to track the busy time
- * and any gpu specific performance counters that are supported.
- */
-
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-
-#include <drm/drm_file.h>
-
-#include "msm_drv.h"
-#include "msm_gpu.h"
-
-struct msm_perf_state {
- struct drm_device *dev;
-
- bool open;
- int cnt;
- struct mutex read_lock;
-
- char buf[256];
- int buftot, bufpos;
-
- unsigned long next_jiffies;
-};
-
-#define SAMPLE_TIME (HZ/4)
-
-/* wait for next sample time: */
-static int wait_sample(struct msm_perf_state *perf)
-{
- unsigned long start_jiffies = jiffies;
-
- if (time_after(perf->next_jiffies, start_jiffies)) {
- unsigned long remaining_jiffies =
- perf->next_jiffies - start_jiffies;
- int ret = schedule_timeout_interruptible(remaining_jiffies);
- if (ret > 0) {
- /* interrupted */
- return -ERESTARTSYS;
- }
- }
- perf->next_jiffies += SAMPLE_TIME;
- return 0;
-}
-
-static int refill_buf(struct msm_perf_state *perf)
-{
- struct msm_drm_private *priv = perf->dev->dev_private;
- struct msm_gpu *gpu = priv->gpu;
- char *ptr = perf->buf;
- int rem = sizeof(perf->buf);
- int i, n;
-
- if ((perf->cnt++ % 32) == 0) {
- /* Header line: */
- n = scnprintf(ptr, rem, "%%BUSY");
- ptr += n;
- rem -= n;
-
- for (i = 0; i < gpu->num_perfcntrs; i++) {
- const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i];
- n = scnprintf(ptr, rem, "\t%s", perfcntr->name);
- ptr += n;
- rem -= n;
- }
- } else {
- /* Sample line: */
- uint32_t activetime = 0, totaltime = 0;
- uint32_t cntrs[5];
- uint32_t val;
- int ret;
-
- /* sleep until next sample time: */
- ret = wait_sample(perf);
- if (ret)
- return ret;
-
- ret = msm_gpu_perfcntr_sample(gpu, &activetime, &totaltime,
- ARRAY_SIZE(cntrs), cntrs);
- if (ret < 0)
- return ret;
-
- val = totaltime ? 1000 * activetime / totaltime : 0;
- n = scnprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10);
- ptr += n;
- rem -= n;
-
- for (i = 0; i < ret; i++) {
- /* cycle counters (I think).. convert to MHz.. */
- val = cntrs[i] / 10000;
- n = scnprintf(ptr, rem, "\t%5d.%02d",
- val / 100, val % 100);
- ptr += n;
- rem -= n;
- }
- }
-
- n = scnprintf(ptr, rem, "\n");
- ptr += n;
- rem -= n;
-
- perf->bufpos = 0;
- perf->buftot = ptr - perf->buf;
-
- return 0;
-}
-
-static ssize_t perf_read(struct file *file, char __user *buf,
- size_t sz, loff_t *ppos)
-{
- struct msm_perf_state *perf = file->private_data;
- int n = 0, ret = 0;
-
- mutex_lock(&perf->read_lock);
-
- if (perf->bufpos >= perf->buftot) {
- ret = refill_buf(perf);
- if (ret)
- goto out;
- }
-
- n = min((int)sz, perf->buftot - perf->bufpos);
- if (copy_to_user(buf, &perf->buf[perf->bufpos], n)) {
- ret = -EFAULT;
- goto out;
- }
-
- perf->bufpos += n;
- *ppos += n;
-
-out:
- mutex_unlock(&perf->read_lock);
- if (ret)
- return ret;
- return n;
-}
-
-static int perf_open(struct inode *inode, struct file *file)
-{
- struct msm_perf_state *perf = inode->i_private;
- struct drm_device *dev = perf->dev;
- struct msm_drm_private *priv = dev->dev_private;
- struct msm_gpu *gpu = priv->gpu;
- int ret = 0;
-
- if (!gpu)
- return -ENODEV;
-
- mutex_lock(&gpu->lock);
-
- if (perf->open) {
- ret = -EBUSY;
- goto out;
- }
-
- file->private_data = perf;
- perf->open = true;
- perf->cnt = 0;
- perf->buftot = 0;
- perf->bufpos = 0;
- msm_gpu_perfcntr_start(gpu);
- perf->next_jiffies = jiffies + SAMPLE_TIME;
-
-out:
- mutex_unlock(&gpu->lock);
- return ret;
-}
-
-static int perf_release(struct inode *inode, struct file *file)
-{
- struct msm_perf_state *perf = inode->i_private;
- struct msm_drm_private *priv = perf->dev->dev_private;
- msm_gpu_perfcntr_stop(priv->gpu);
- perf->open = false;
- return 0;
-}
-
-
-static const struct file_operations perf_debugfs_fops = {
- .owner = THIS_MODULE,
- .open = perf_open,
- .read = perf_read,
- .release = perf_release,
-};
-
-int msm_perf_debugfs_init(struct drm_minor *minor)
-{
- struct msm_drm_private *priv = minor->dev->dev_private;
- struct msm_perf_state *perf;
-
- /* only create on first minor: */
- if (priv->perf)
- return 0;
-
- perf = kzalloc_obj(*perf);
- if (!perf)
- return -ENOMEM;
-
- perf->dev = minor->dev;
-
- mutex_init(&perf->read_lock);
- priv->perf = perf;
-
- debugfs_create_file("perf", S_IFREG | S_IRUGO, minor->debugfs_root,
- perf, &perf_debugfs_fops);
- return 0;
-}
-
-void msm_perf_debugfs_cleanup(struct msm_drm_private *priv)
-{
- struct msm_perf_state *perf = priv->perf;
-
- if (!perf)
- return;
-
- priv->perf = NULL;
-
- mutex_destroy(&perf->read_lock);
-
- kfree(perf);
-}
-
-#endif