mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-23 22:27:01 -04:00
The Arm Ethos-U NPUs have a PMU with performance counters. The PMU h/w supports up to 4 (U65) or 8 (U85) counters which can be programmed for different events. There is also a dedicated cycle counter. The ABI and implementation are copied from the V3D driver. The main difference in the ABI is there is no query API for the event list. The events differ between the U65 and U85, so the events lists are maintained in userspace along with other differences between the U65 and U85. The cycle counter is always enabled when the PMU is enabled. When the user requests N events, reading the counters will return the N events plus the cycle counter. Signed-off-by: Rob Herring (Arm) <robh@kernel.org> Signed-off-by: Tomeu Vizoso <tomeu@tomeuvizoso.net> Reviewed-by: Maíra Canal <mcanal@igalia.com> Link: https://patch.msgid.link/20260601173814.250071-1-tomeu@tomeuvizoso.net --- v2: - Use XArray instead of idr - Rework locking to use per device spinlock to protect modifying active perfmon. Based on pending V3D changes: https://lore.kernel.org/all/20260508-v3d-perfmon-lifetime-v1-1-f5b5642c085f@igalia.com/ - Add missing perfmon puts in ethosu_ioctl_perfmon_set_global() and ethosu_ioctl_perfmon_get_values() error paths. - Fix reading number of counters on U85. - Add defines NPU_REG_PMCCNTR_CFG v3: - Add explicit padding to drm_ethosu_perfmon_destroy - Fix SPDX license expression - Fix comment typos - Convert perfmon lock from spinlock to mutex - Simplify switch_perfmon condition check - Remove unused ethosu_perfmon_init - Add lockdep_assert_held to ethosu_perfmon_stop_locked v4: - Use drmm_mutex_init() for perfmon lock - Add lockdep_assert_held() to ethosu_perfmon_start() - Fix a few style issues reported by Maíra
320 lines
8.0 KiB
C
320 lines
8.0 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
/* Copyright (C) 2025 Arm, Ltd. */
|
|
#ifndef _ETHOSU_DRM_H_
|
|
#define _ETHOSU_DRM_H_
|
|
|
|
#include "drm.h"
|
|
|
|
#if defined(__cplusplus)
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* DOC: IOCTL IDs
|
|
*
|
|
* enum drm_ethosu_ioctl_id - IOCTL IDs
|
|
*
|
|
* Place new ioctls at the end, don't re-order, don't replace or remove entries.
|
|
*
|
|
* These IDs are not meant to be used directly. Use the DRM_IOCTL_ETHOSU_xxx
|
|
* definitions instead.
|
|
*/
|
|
enum drm_ethosu_ioctl_id {
|
|
/** @DRM_ETHOSU_DEV_QUERY: Query device information. */
|
|
DRM_ETHOSU_DEV_QUERY = 0,
|
|
|
|
/** @DRM_ETHOSU_BO_CREATE: Create a buffer object. */
|
|
DRM_ETHOSU_BO_CREATE,
|
|
|
|
/** @DRM_ETHOSU_BO_WAIT: Wait on a buffer object's fence. */
|
|
DRM_ETHOSU_BO_WAIT,
|
|
|
|
/**
|
|
* @DRM_ETHOSU_BO_MMAP_OFFSET: Get the file offset to pass to
|
|
* mmap to map a GEM object.
|
|
*/
|
|
DRM_ETHOSU_BO_MMAP_OFFSET,
|
|
|
|
/**
|
|
* @DRM_ETHOSU_CMDSTREAM_BO_CREATE: Create a command stream buffer
|
|
* object.
|
|
*/
|
|
DRM_ETHOSU_CMDSTREAM_BO_CREATE,
|
|
|
|
/** @DRM_ETHOSU_SUBMIT: Submit a job and BOs to run. */
|
|
DRM_ETHOSU_SUBMIT,
|
|
|
|
DRM_ETHOSU_PERFMON_CREATE,
|
|
DRM_ETHOSU_PERFMON_DESTROY,
|
|
DRM_ETHOSU_PERFMON_GET_VALUES,
|
|
DRM_ETHOSU_PERFMON_SET_GLOBAL,
|
|
};
|
|
|
|
/**
|
|
* DOC: IOCTL arguments
|
|
*/
|
|
|
|
/**
|
|
* enum drm_ethosu_dev_query_type - Query type
|
|
*
|
|
* Place new types at the end, don't re-order, don't remove or replace.
|
|
*/
|
|
enum drm_ethosu_dev_query_type {
|
|
/** @DRM_ETHOSU_DEV_QUERY_NPU_INFO: Query NPU information. */
|
|
DRM_ETHOSU_DEV_QUERY_NPU_INFO = 0,
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_gpu_info - NPU information
|
|
*
|
|
* Structure grouping all queryable information relating to the NPU.
|
|
*/
|
|
struct drm_ethosu_npu_info {
|
|
/** @id : NPU ID. */
|
|
__u32 id;
|
|
#define DRM_ETHOSU_ARCH_MAJOR(x) ((x) >> 28)
|
|
#define DRM_ETHOSU_ARCH_MINOR(x) (((x) >> 20) & 0xff)
|
|
#define DRM_ETHOSU_ARCH_PATCH(x) (((x) >> 16) & 0xf)
|
|
#define DRM_ETHOSU_PRODUCT_MAJOR(x) (((x) >> 12) & 0xf)
|
|
#define DRM_ETHOSU_VERSION_MAJOR(x) (((x) >> 8) & 0xf)
|
|
#define DRM_ETHOSU_VERSION_MINOR(x) (((x) >> 4) & 0xff)
|
|
#define DRM_ETHOSU_VERSION_STATUS(x) ((x) & 0xf)
|
|
|
|
/** @gpu_rev: GPU revision. */
|
|
__u32 config;
|
|
|
|
__u32 sram_size;
|
|
__u32 pmu_counters;
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_dev_query - Arguments passed to DRM_ETHOSU_IOCTL_DEV_QUERY
|
|
*/
|
|
struct drm_ethosu_dev_query {
|
|
/** @type: the query type (see drm_ethosu_dev_query_type). */
|
|
__u32 type;
|
|
|
|
/**
|
|
* @size: size of the type being queried.
|
|
*
|
|
* If pointer is NULL, size is updated by the driver to provide the
|
|
* output structure size. If pointer is not NULL, the driver will
|
|
* only copy min(size, actual_structure_size) bytes to the pointer,
|
|
* and update the size accordingly. This allows us to extend query
|
|
* types without breaking userspace.
|
|
*/
|
|
__u32 size;
|
|
|
|
/**
|
|
* @pointer: user pointer to a query type struct.
|
|
*
|
|
* Pointer can be NULL, in which case, nothing is copied, but the
|
|
* actual structure size is returned. If not NULL, it must point to
|
|
* a location that's large enough to hold size bytes.
|
|
*/
|
|
__u64 pointer;
|
|
};
|
|
|
|
/**
|
|
* enum drm_ethosu_bo_flags - Buffer object flags, passed at creation time.
|
|
*/
|
|
enum drm_ethosu_bo_flags {
|
|
/**
|
|
* @DRM_ETHOSU_BO_NO_MMAP: The buffer object will never be CPU-mapped
|
|
* in userspace.
|
|
*/
|
|
DRM_ETHOSU_BO_NO_MMAP = (1 << 0),
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_bo_create - Arguments passed to DRM_IOCTL_ETHOSU_BO_CREATE.
|
|
*/
|
|
struct drm_ethosu_bo_create {
|
|
/**
|
|
* @size: Requested size for the object
|
|
*
|
|
* The (page-aligned) allocated size for the object will be returned.
|
|
*/
|
|
__u64 size;
|
|
|
|
/**
|
|
* @flags: Flags. Must be a combination of drm_ethosu_bo_flags flags.
|
|
*/
|
|
__u32 flags;
|
|
|
|
/**
|
|
* @handle: Returned handle for the object.
|
|
*
|
|
* Object handles are nonzero.
|
|
*/
|
|
__u32 handle;
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_bo_mmap_offset - Arguments passed to DRM_IOCTL_ETHOSU_BO_MMAP_OFFSET.
|
|
*/
|
|
struct drm_ethosu_bo_mmap_offset {
|
|
/** @handle: Handle of the object we want an mmap offset for. */
|
|
__u32 handle;
|
|
|
|
/** @pad: MBZ. */
|
|
__u32 pad;
|
|
|
|
/** @offset: The fake offset to use for subsequent mmap calls. */
|
|
__u64 offset;
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_wait_bo - ioctl argument for waiting for
|
|
* completion of the last DRM_ETHOSU_SUBMIT on a BO.
|
|
*
|
|
* This is useful for cases where multiple processes might be
|
|
* rendering to a BO and you want to wait for all rendering to be
|
|
* completed.
|
|
*/
|
|
struct drm_ethosu_bo_wait {
|
|
__u32 handle;
|
|
__u32 pad;
|
|
__s64 timeout_ns; /* absolute */
|
|
};
|
|
|
|
struct drm_ethosu_cmdstream_bo_create {
|
|
/* Size of the data argument. */
|
|
__u32 size;
|
|
|
|
/* Flags, currently must be 0. */
|
|
__u32 flags;
|
|
|
|
/* Pointer to the data. */
|
|
__u64 data;
|
|
|
|
/** Returned GEM handle for the BO. */
|
|
__u32 handle;
|
|
|
|
/* Pad, must be 0. */
|
|
__u32 pad;
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_job - A job to be run on the NPU
|
|
*
|
|
* The kernel will schedule the execution of this job taking into account its
|
|
* dependencies with other jobs. All tasks in the same job will be executed
|
|
* sequentially on the same core, to benefit from memory residency in SRAM.
|
|
*/
|
|
struct drm_ethosu_job {
|
|
/** Input: BO handle for cmdstream. */
|
|
__u32 cmd_bo;
|
|
|
|
/** Input: Amount of SRAM to use. */
|
|
__u32 sram_size;
|
|
|
|
#define ETHOSU_MAX_REGIONS 8
|
|
/** Input: Array of BO handles for each region. */
|
|
__u32 region_bo_handles[ETHOSU_MAX_REGIONS];
|
|
};
|
|
|
|
/**
|
|
* struct drm_ethosu_submit - ioctl argument for submitting commands to the NPU.
|
|
*
|
|
* The kernel will schedule the execution of these jobs in dependency order.
|
|
*/
|
|
struct drm_ethosu_submit {
|
|
/** Input: Pointer to an array of struct drm_ethosu_job. */
|
|
__u64 jobs;
|
|
|
|
/** Input: Number of jobs passed in. */
|
|
__u32 job_count;
|
|
|
|
/** Input: Id returned by DRM_ETHOSU_PERFMON_CREATE */
|
|
__u32 perfmon_id;
|
|
};
|
|
|
|
#define DRM_ETHOSU_MAX_PERF_EVENT_COUNTERS 8
|
|
#define DRM_ETHOSU_MAX_PERF_COUNTERS \
|
|
(DRM_ETHOSU_MAX_PERF_EVENT_COUNTERS + 1)
|
|
|
|
struct drm_ethosu_perfmon_create {
|
|
__u32 id;
|
|
__u32 ncounters;
|
|
__u16 counters[DRM_ETHOSU_MAX_PERF_EVENT_COUNTERS];
|
|
};
|
|
|
|
struct drm_ethosu_perfmon_destroy {
|
|
__u32 id;
|
|
__u32 pad;
|
|
};
|
|
|
|
/*
|
|
* Returns the values of the performance counters tracked by this
|
|
* perfmon (as an array of (ncounters + 1) u64 values).
|
|
*
|
|
* No implicit synchronization is performed, so the user has to
|
|
* guarantee that any jobs using this perfmon have already been
|
|
* completed.
|
|
*/
|
|
struct drm_ethosu_perfmon_get_values {
|
|
__u32 id;
|
|
__u32 pad;
|
|
__u64 values_ptr;
|
|
};
|
|
|
|
#define DRM_ETHOSU_PERFMON_CLEAR_GLOBAL 0x0001
|
|
|
|
/**
|
|
* struct drm_ethosu_perfmon_set_global - ioctl to define a global performance
|
|
* monitor
|
|
*
|
|
* The global performance monitor will be used for all jobs. If a global
|
|
* performance monitor is defined, jobs with a self-defined performance
|
|
* monitor won't be allowed.
|
|
*/
|
|
struct drm_ethosu_perfmon_set_global {
|
|
__u32 flags;
|
|
__u32 id;
|
|
};
|
|
|
|
/**
|
|
* DRM_IOCTL_ETHOSU() - Build a ethosu IOCTL number
|
|
* @__access: Access type. Must be R, W or RW.
|
|
* @__id: One of the DRM_ETHOSU_xxx id.
|
|
* @__type: Suffix of the type being passed to the IOCTL.
|
|
*
|
|
* Don't use this macro directly, use the DRM_IOCTL_ETHOSU_xxx
|
|
* values instead.
|
|
*
|
|
* Return: An IOCTL number to be passed to ioctl() from userspace.
|
|
*/
|
|
#define DRM_IOCTL_ETHOSU(__access, __id, __type) \
|
|
DRM_IO ## __access(DRM_COMMAND_BASE + DRM_ETHOSU_ ## __id, \
|
|
struct drm_ethosu_ ## __type)
|
|
|
|
enum {
|
|
DRM_IOCTL_ETHOSU_DEV_QUERY =
|
|
DRM_IOCTL_ETHOSU(WR, DEV_QUERY, dev_query),
|
|
DRM_IOCTL_ETHOSU_BO_CREATE =
|
|
DRM_IOCTL_ETHOSU(WR, BO_CREATE, bo_create),
|
|
DRM_IOCTL_ETHOSU_BO_WAIT =
|
|
DRM_IOCTL_ETHOSU(WR, BO_WAIT, bo_wait),
|
|
DRM_IOCTL_ETHOSU_BO_MMAP_OFFSET =
|
|
DRM_IOCTL_ETHOSU(WR, BO_MMAP_OFFSET, bo_mmap_offset),
|
|
DRM_IOCTL_ETHOSU_CMDSTREAM_BO_CREATE =
|
|
DRM_IOCTL_ETHOSU(WR, CMDSTREAM_BO_CREATE, cmdstream_bo_create),
|
|
DRM_IOCTL_ETHOSU_SUBMIT =
|
|
DRM_IOCTL_ETHOSU(WR, SUBMIT, submit),
|
|
DRM_IOCTL_ETHOSU_PERFMON_CREATE =
|
|
DRM_IOCTL_ETHOSU(WR, PERFMON_CREATE, perfmon_create),
|
|
DRM_IOCTL_ETHOSU_PERFMON_DESTROY =
|
|
DRM_IOCTL_ETHOSU(WR, PERFMON_DESTROY, perfmon_destroy),
|
|
DRM_IOCTL_ETHOSU_PERFMON_GET_VALUES =
|
|
DRM_IOCTL_ETHOSU(WR, PERFMON_GET_VALUES, perfmon_get_values),
|
|
DRM_IOCTL_ETHOSU_PERFMON_SET_GLOBAL =
|
|
DRM_IOCTL_ETHOSU(WR, PERFMON_SET_GLOBAL, perfmon_set_global),
|
|
};
|
|
|
|
#if defined(__cplusplus)
|
|
}
|
|
#endif
|
|
|
|
#endif /* _ETHOSU_DRM_H_ */
|