diff --git a/src/panfrost/lib/kmod/panfrost_kmod.c b/src/panfrost/lib/kmod/panfrost_kmod.c index a3d8900c251..e7a0c1c2cdd 100644 --- a/src/panfrost/lib/kmod/panfrost_kmod.c +++ b/src/panfrost/lib/kmod/panfrost_kmod.c @@ -42,6 +42,10 @@ struct panfrost_kmod_bo { uint64_t offset; }; +struct panfrost_kmod_perf_session { + struct pan_kmod_perf_session base; +}; + /* Abstraction over the raw drm_panfrost_get_param ioctl for fetching * information about devices. */ @@ -607,6 +611,106 @@ panfrost_kmod_bo_label(struct pan_kmod_dev *dev, struct pan_kmod_bo *bo, const c mesa_loge("DRM_IOCTL_PANFROST_SET_LABEL_BO failed (err=%d)", errno); } +static inline struct pan_kmod_perf_session * +panfrost_kmod_perf_init(struct pan_kmod_dev *dev) +{ + UNUSED struct panfrost_kmod_dev *panfrost_dev = + container_of(dev, struct panfrost_kmod_dev, base); + + struct panfrost_kmod_perf_session *sess = + pan_kmod_dev_alloc(dev, sizeof(*sess)); + if (!sess) { + mesa_loge("failed to allocate a panfrost_kmod_perf_session object"); + return NULL; + } + + sess->base.dev = dev; + + struct pan_kmod_perf_buffer_layout layout; + pan_kmod_perf_query_layout(&sess->base, &layout); + + uint32_t n_counters = 0; + for (uint32_t cat = 0; cat < PAN_KMOD_PERF_CAT_COUNT; ++cat) + n_counters += layout.category[cat].n_blocks * layout.counters_per_category; + + uint32_t* counter_values = pan_kmod_dev_alloc(dev, sizeof(uint32_t) * n_counters); + sess->base.data = counter_values; + sess->base.data_ts_supported = false; + + mesa_logd("perf session created"); + + return &(sess->base); +} + +static int +panfrost_kmod_perf_query(struct pan_kmod_perf_session *session, uint32_t enable) +{ + struct drm_panfrost_perfcnt_enable perfcnt_enable = {enable, 0}; + return pan_kmod_ioctl(session->dev->fd, DRM_IOCTL_PANFROST_PERFCNT_ENABLE, + &perfcnt_enable); +} + +static int +panfrost_kmod_perf_enable(struct pan_kmod_perf_session *session) +{ + return panfrost_kmod_perf_query(session, 1 /* enable */); +} + +static int +panfrost_kmod_perf_disable(struct pan_kmod_perf_session *session) +{ + return panfrost_kmod_perf_query(session, 0 /* disable */); +} + +static int +panfrost_kmod_perf_dump(struct pan_kmod_perf_session *session) +{ + struct drm_panfrost_perfcnt_dump perfcnt_dump = { + (uint64_t)(uintptr_t)session->data}; + return pan_kmod_ioctl(session->dev->fd, DRM_IOCTL_PANFROST_PERFCNT_DUMP, + &perfcnt_dump); +} + +static void +panfrost_kmod_perf_query_layout(const struct pan_kmod_perf_session *session, + struct pan_kmod_perf_buffer_layout *layout) +{ + /* Generally counter blocks are laid out in the following order: + * Job manager, tiler, one or more L2 caches, and one or more shader cores. + */ + unsigned l2_slices = pan_query_l2_slices(&session->dev->props); + unsigned core_id_range; + pan_query_core_count(&session->dev->props, &core_id_range); + + /* On all Bifrost architectures this is 64. */ + const unsigned counters_per_cat = 64; + layout->counters_per_category = counters_per_cat; + layout->counter_stride = sizeof(uint32_t); + layout->block_stride = counters_per_cat * sizeof(uint32_t); + + /* Setup the layout */ + layout->category[PAN_KMOD_PERF_CAT_FRONTEND].n_blocks = 1; + layout->category[PAN_KMOD_PERF_CAT_TILER].n_blocks = 1; + layout->category[PAN_KMOD_PERF_CAT_MEMSYS].n_blocks = l2_slices; + layout->category[PAN_KMOD_PERF_CAT_SHADER].n_blocks = core_id_range; + + layout->category[0].offset = 0; + for (unsigned cat_idx = 1; cat_idx < PAN_KMOD_PERF_CAT_COUNT; ++cat_idx) { + layout->category[cat_idx].offset = + layout->category[cat_idx - 1].offset + + layout->category[cat_idx - 1].n_blocks * counters_per_cat; + } +} + +static void +panfrost_kmod_perf_destroy(struct pan_kmod_perf_session *session) +{ + if (session->data) + pan_kmod_dev_free(session->dev, session->data); + pan_kmod_dev_free(session->dev, session); + mesa_logd("perf session destroyed"); +} + const struct pan_kmod_ops panfrost_kmod_ops = { .dev_create = panfrost_kmod_dev_create, .dev_destroy = panfrost_kmod_dev_destroy, @@ -624,4 +728,10 @@ const struct pan_kmod_ops panfrost_kmod_ops = { .vm_bind = panfrost_kmod_vm_bind, .query_timestamp = panfrost_kmod_query_timestamp, .bo_set_label = panfrost_kmod_bo_label, + .perf_create = panfrost_kmod_perf_init, + .perf_enable = panfrost_kmod_perf_enable, + .perf_disable = panfrost_kmod_perf_disable, + .perf_dump = panfrost_kmod_perf_dump, + .perf_query_layout = panfrost_kmod_perf_query_layout, + .perf_destroy = panfrost_kmod_perf_destroy, };