linux/drivers/gpu/drm/msm/msm_perfcntr.h
Rob Clark a7b378c949 drm/msm: Add PERFCNTR_CONFIG ioctl
Add new UABI and implementation of PERFCNTR_CONFIG ioctl.

A bit more work is required to configure the pwrup_reglist for the GMU
to restore SELect regs on exit of IFPC, before we can stop disabling
IFPC while global counter collection.  This will follow in a later
commit, but will be transparent to userspace.

Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
Reviewed-by: Anna Maniscalco <anna.maniscalco2000@gmail.com>
Reviewed-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/728217/
Message-ID: <20260526145137.160554-14-robin.clark@oss.qualcomm.com>
2026-05-29 07:07:29 -07:00

156 lines
4.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef __MSM_PERFCNTR_H__
#define __MSM_PERFCNTR_H__
#include "linux/array_size.h"
#include "linux/circ_buf.h"
#include "linux/hrtimer.h"
#include "linux/kthread.h"
#include "linux/wait.h"
#include "linux/workqueue.h"
#include "adreno_common.xml.h"
/*
* This is a subset of the tables used by mesa. We don't need to
* enumerate the countables on the kernel side.
*/
/* Describes a single counter: */
struct msm_perfcntr_counter {
/* offset of the SELect register to choose what to count: */
unsigned select_reg;
/* additional SEL regs to enable slice counters (gen8+) */
unsigned slice_select_regs[2];
/* offset of the lo/hi 32b to read current counter value: */
unsigned counter_reg_lo;
unsigned counter_reg_hi;
/* TODO some counters have enable/clear registers */
};
/* Describes an entire counter group: */
struct msm_perfcntr_group {
const char *name;
enum adreno_pipe pipe;
unsigned num_counters;
const struct msm_perfcntr_counter *counters;
};
/**
* struct msm_perfcntr_stream - state for a single open stream fd
*/
struct msm_perfcntr_stream {
/** @gpu: Back-link to the GPU */
struct msm_gpu *gpu;
/** @sample_timer: Timer to sample counters */
struct hrtimer sample_timer;
/** @poll_wq: Wait queue for waiting for OA data to be available */
wait_queue_head_t poll_wq;
/** @sample_period_ns: Sampling period */
uint64_t sample_period_ns;
/** @nr_groups: # of counter groups with enabled counters */
uint32_t nr_groups;
/** @seqno: counter for collected samples */
uint32_t seqno;
/** @sel_fence: Fence for SEL reg programming */
uint32_t sel_fence;
/**
* @sel_work: Worker for SEL reg programming
*
* Initial SEL reg programming (as opposed to restoring the SEL
* regs on runpm resume) must run on the same ordered wq as is
* used by drm_sched, to serialize it with GEM_SUBMITs written
* into the same ringbuffer.
*/
struct work_struct sel_work;
/**
* @sample_work: Worker for collecting samples
*/
struct kthread_work sample_work;
/**
* @read_lock:
*
* Fifo access is synchronied on the producer side by virtue
* of there being a single timer collecting samples and writing
* into the fifo. It is protected on the consumer side by
* @read_lock.
*/
struct mutex read_lock;
/**
* @group_idx: array of nr_groups
*
* Maps the order of groups in PERFCNTR_CONFIG ioctl to group idx,
* so that results in the results stream can be ordered to match
* the ioctl call that setup the stream
*/
uint32_t *group_idx;
/** @fifo: circular buffer for samples */
struct circ_buf fifo;
/** @fifo_size: circular buffer size */
size_t fifo_size;
/** @period_size: size of data for single sampling period */
size_t period_size;
};
uint32_t msm_perfcntr_group_idx(const struct msm_perfcntr_stream *stream, uint32_t n);
uint32_t msm_perfcntr_counter_base(const struct msm_perfcntr_stream *stream, uint32_t group_idx);
/**
* struct msm_perfcntr_context_state - per-msm_context counter state
*
* A given counter can either be unused, reserved for global counter
* collection exclusively, or reserved for local per-context counter
* collection inclusively. Multiple contexts can reserve the same
* counter, since SEL reg programming and counter begin/end sampling
* happen locally (within a single GEM_SUBMIT ioctl).
*/
struct msm_perfcntr_context_state {
/** @dummy: Some compilers dislike structs with only a flex array */
unsigned dummy;
/**
* @reserved_counters:
*
* The number of reserved counters indexed by perfcntr group.
*/
unsigned reserved_counters[];
};
extern const struct msm_perfcntr_group a6xx_perfcntr_groups[];
extern const unsigned a6xx_num_perfcntr_groups;
extern const struct msm_perfcntr_group a7xx_perfcntr_groups[];
extern const unsigned a7xx_num_perfcntr_groups;
extern const struct msm_perfcntr_group a8xx_perfcntr_groups[];
extern const unsigned a8xx_num_perfcntr_groups;
#define GROUP(_name, _pipe, _counters, _countables) { \
.name = _name, \
.pipe = _pipe, \
.num_counters = ARRAY_SIZE(_counters), \
.counters = _counters, \
}
#define fd_perfcntr_counter msm_perfcntr_counter
#define fd_perfcntr_group msm_perfcntr_group
#endif /* __MSM_PERFCNTR_H__ */