drm/panfrost: Replace fdinfo's profiling debugfs knob with sysfs

Debugfs isn't always available in production builds that try to squeeze
every single byte out of the kernel image, but we still need a way to
toggle the timestamp and cycle counter registers so that jobs can be
profiled for fdinfo's drm engine and cycle calculations.

Drop the debugfs knob and replace it with a sysfs file that accomplishes
the same functionality, and document its ABI in a separate file.

Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240306015819.822128-2-adrian.larumbe@collabora.com
This commit is contained in:
Adrián Larumbe 2024-03-06 01:56:36 +00:00 committed by Boris Brezillon
parent 57a4e3a94c
commit b12f3ea7c1
8 changed files with 56 additions and 44 deletions

View File

@ -0,0 +1,10 @@
What: /sys/bus/platform/drivers/panfrost/.../profiling
Date: February 2024
KernelVersion: 6.8.0
Contact: Adrian Larumbe <adrian.larumbe@collabora.com>
Description:
Get/set drm fdinfo's engine and cycles profiling status.
Valid values are:
0: Don't enable fdinfo job profiling sources.
1: Enable fdinfo job profiling sources, this enables both the GPU's
timestamp and cycle counter registers.

View File

@ -38,3 +38,12 @@ the currently possible format options:
Possible `drm-engine-` key names are: `fragment`, and `vertex-tiler`. Possible `drm-engine-` key names are: `fragment`, and `vertex-tiler`.
`drm-curfreq-` values convey the current operating frequency for that engine. `drm-curfreq-` values convey the current operating frequency for that engine.
Users must bear in mind that engine and cycle sampling are disabled by default,
because of power saving concerns. `fdinfo` users and benchmark applications which
query the fdinfo file must make sure to toggle the job profiling status of the
driver by writing into the appropriate sysfs node::
echo <N> > /sys/bus/platform/drivers/panfrost/[a-f0-9]*.gpu/profiling
Where `N` is either `0` or `1`, depending on the desired enablement status.

View File

@ -12,6 +12,4 @@ panfrost-y := \
panfrost_perfcnt.o \ panfrost_perfcnt.o \
panfrost_dump.o panfrost_dump.o
panfrost-$(CONFIG_DEBUG_FS) += panfrost_debugfs.o
obj-$(CONFIG_DRM_PANFROST) += panfrost.o obj-$(CONFIG_DRM_PANFROST) += panfrost.o

View File

@ -1,21 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2023 Collabora ltd. */
/* Copyright 2023 Amazon.com, Inc. or its affiliates. */
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_file.h>
#include <drm/panfrost_drm.h>
#include "panfrost_device.h"
#include "panfrost_gpu.h"
#include "panfrost_debugfs.h"
void panfrost_debugfs_init(struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev->dev));
debugfs_create_atomic_t("profile", 0600, minor->debugfs_root, &pfdev->profile_mode);
}

View File

@ -1,14 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2023 Collabora ltd.
* Copyright 2023 Amazon.com, Inc. or its affiliates.
*/
#ifndef PANFROST_DEBUGFS_H
#define PANFROST_DEBUGFS_H
#ifdef CONFIG_DEBUG_FS
void panfrost_debugfs_init(struct drm_minor *minor);
#endif
#endif /* PANFROST_DEBUGFS_H */

View File

@ -130,7 +130,7 @@ struct panfrost_device {
struct list_head scheduled_jobs; struct list_head scheduled_jobs;
struct panfrost_perfcnt *perfcnt; struct panfrost_perfcnt *perfcnt;
atomic_t profile_mode; bool profile_mode;
struct mutex sched_lock; struct mutex sched_lock;

View File

@ -20,7 +20,6 @@
#include "panfrost_job.h" #include "panfrost_job.h"
#include "panfrost_gpu.h" #include "panfrost_gpu.h"
#include "panfrost_perfcnt.h" #include "panfrost_perfcnt.h"
#include "panfrost_debugfs.h"
static bool unstable_ioctls; static bool unstable_ioctls;
module_param_unsafe(unstable_ioctls, bool, 0600); module_param_unsafe(unstable_ioctls, bool, 0600);
@ -600,10 +599,6 @@ static const struct drm_driver panfrost_drm_driver = {
.gem_create_object = panfrost_gem_create_object, .gem_create_object = panfrost_gem_create_object,
.gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = panfrost_debugfs_init,
#endif
}; };
static int panfrost_probe(struct platform_device *pdev) static int panfrost_probe(struct platform_device *pdev)
@ -692,6 +687,40 @@ static void panfrost_remove(struct platform_device *pdev)
drm_dev_put(ddev); drm_dev_put(ddev);
} }
static ssize_t profiling_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", pfdev->profile_mode);
}
static ssize_t profiling_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
bool value;
int err;
err = kstrtobool(buf, &value);
if (err)
return err;
pfdev->profile_mode = value;
return len;
}
static DEVICE_ATTR_RW(profiling);
static struct attribute *panfrost_attrs[] = {
&dev_attr_profiling.attr,
NULL,
};
ATTRIBUTE_GROUPS(panfrost);
/* /*
* The OPP core wants the supply names to be NULL terminated, but we need the * The OPP core wants the supply names to be NULL terminated, but we need the
* correct num_supplies value for regulator core. Hence, we NULL terminate here * correct num_supplies value for regulator core. Hence, we NULL terminate here
@ -789,6 +818,7 @@ static struct platform_driver panfrost_driver = {
.name = "panfrost", .name = "panfrost",
.pm = pm_ptr(&panfrost_pm_ops), .pm = pm_ptr(&panfrost_pm_ops),
.of_match_table = dt_match, .of_match_table = dt_match,
.dev_groups = panfrost_groups,
}, },
}; };
module_platform_driver(panfrost_driver); module_platform_driver(panfrost_driver);

View File

@ -243,7 +243,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js)
subslot = panfrost_enqueue_job(pfdev, js, job); subslot = panfrost_enqueue_job(pfdev, js, job);
/* Don't queue the job if a reset is in progress */ /* Don't queue the job if a reset is in progress */
if (!atomic_read(&pfdev->reset.pending)) { if (!atomic_read(&pfdev->reset.pending)) {
if (atomic_read(&pfdev->profile_mode)) { if (pfdev->profile_mode) {
panfrost_cycle_counter_get(pfdev); panfrost_cycle_counter_get(pfdev);
job->is_profiled = true; job->is_profiled = true;
job->start_time = ktime_get(); job->start_time = ktime_get();