diff --git a/src/panfrost/lib/kmod/pan_kmod.h b/src/panfrost/lib/kmod/pan_kmod.h index e7356330e7d..8076e78a5bb 100644 --- a/src/panfrost/lib/kmod/pan_kmod.h +++ b/src/panfrost/lib/kmod/pan_kmod.h @@ -1,5 +1,6 @@ /* * Copyright © 2023 Collabora, Ltd. + * Copyright © 2026 Arm Ltd. * SPDX-License-Identifier: MIT */ @@ -37,6 +38,7 @@ #include "util/u_dynarray.h" #include "kmod/panthor_kmod.h" +#include "pan_props.h" #include "pan_trace.h" #if defined(__cplusplus) @@ -384,6 +386,54 @@ struct pan_kmod_va_range { uint64_t size; }; +struct pan_kmod_perf_session { + /* Device this perf session was created from. */ + struct pan_kmod_dev *dev; + + /* Sample data pointer. */ + void* data; + + /* If pan_kmod_perf_session::data_ts is supported. */ + bool data_ts_supported; + + /* The timestamp of the sample data. */ + uint64_t data_ts; +}; + +enum pan_kmod_perf_category { + PAN_KMOD_PERF_CAT_FRONTEND, + PAN_KMOD_PERF_CAT_TILER, + PAN_KMOD_PERF_CAT_MEMSYS, + PAN_KMOD_PERF_CAT_SHADER, + /* Must be last. */ + PAN_KMOD_PERF_CAT_COUNT, +}; + +/* Describes the memory layout of a buffer containing performance counters. + * The buffer is structured like this: + * sample { + * header + * categories [ category { + * blocks [ block { + * header + * samples + * }] + * }] + * } + */ +struct pan_kmod_perf_buffer_layout { + struct { + /* Offset from the start of the buffer in bytes. */ + uint32_t offset; + /* Number of blocks for this category. */ + uint8_t n_blocks; + } category[PAN_KMOD_PERF_CAT_COUNT]; + + uint32_t block_stride; + uint32_t counter_stride; + uint32_t counters_per_category; +}; + /* KMD backend vtable. * * All methods described there are mandatory, unless explicitly flagged as @@ -474,6 +524,25 @@ struct pan_kmod_ops { /* Label the BO */ void (*bo_set_label)(struct pan_kmod_dev *dev, struct pan_kmod_bo *bo, const char *label); + + /* Initialize a perf session. */ + struct pan_kmod_perf_session *(*perf_create)(struct pan_kmod_dev *dev); + + /* Enable perf counters. */ + int (*perf_enable)(struct pan_kmod_perf_session *session); + + /* Disable perf counters. */ + int (*perf_disable)(struct pan_kmod_perf_session *session); + + /* Dump collected perf counters. */ + int (*perf_dump)(struct pan_kmod_perf_session *session); + + /* Destroy a perf session. */ + void (*perf_destroy)(struct pan_kmod_perf_session *session); + + /* Query the memory layout for a counter buffer. */ + void (*perf_query_layout)(const struct pan_kmod_perf_session *session, + struct pan_kmod_perf_buffer_layout *layout); }; /* KMD information. */ @@ -783,6 +852,64 @@ pan_kmod_query_timestamp(const struct pan_kmod_dev *dev) return dev->ops->query_timestamp(dev); } +static inline struct pan_kmod_perf_session * +pan_kmod_perf_create(struct pan_kmod_dev *dev) +{ + return dev->ops->perf_create(dev); +} + +static inline int +pan_kmod_perf_enable(struct pan_kmod_perf_session *session) +{ + return session->dev->ops->perf_enable(session); +} + +static inline int +pan_kmod_perf_disable(struct pan_kmod_perf_session *session) +{ + return session->dev->ops->perf_disable(session); +} + +static inline int +pan_kmod_perf_dump(struct pan_kmod_perf_session *session) +{ + return session->dev->ops->perf_dump(session); +} + +static inline void +pan_kmod_perf_destroy(struct pan_kmod_perf_session *session) +{ + session->dev->ops->perf_destroy(session); +} + +static inline void +pan_kmod_perf_query_layout(const struct pan_kmod_perf_session *session, + struct pan_kmod_perf_buffer_layout *layout) +{ + session->dev->ops->perf_query_layout(session, layout); +} + +/* Load a counter value from the given address. */ +static inline int64_t +pan_kmod_perf_load_counter(const struct pan_kmod_perf_session *session, + const void *ptr) +{ + if (pan_arch(session->dev->props.gpu_id) < 10) + return *((const uint32_t*)ptr); + else { + const uint64_t val = *((const uint64_t*)ptr); +#ifndef NDEBUG + /* + * Even though the uAPI permits 64-bit unsigned counters, the counter + * values realistically never exceed INT64_MAX. + */ + return (val > INT64_MAX) ? -EINVAL : val; +#else + return val; +#endif + } +} + #if defined(__cplusplus) } // extern "C" #endif