From c02697cb9388b48086314fca90758016bd51b8e4 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Mon, 30 Mar 2026 09:37:01 -0700 Subject: accel/amdxdna: Add basic support for AIE4 devices Add initial support for AIE4 devices (PCI device IDs 0x17F2 and 0x1B0B), including: Device initialization Basic mailbox communication SR-IOV enablement This lays the groundwork for full AIE4 support. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260330163705.3153647-3-lizhi.hou@amd.com --- include/uapi/drm/amdxdna_accel.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h index 61d3686fa3b1..0b11e8e3ea5d 100644 --- a/include/uapi/drm/amdxdna_accel.h +++ b/include/uapi/drm/amdxdna_accel.h @@ -29,7 +29,8 @@ extern "C" { enum amdxdna_device_type { AMDXDNA_DEV_TYPE_UNKNOWN = -1, - AMDXDNA_DEV_TYPE_KMQ, + AMDXDNA_DEV_TYPE_KMQ = 0, + AMDXDNA_DEV_TYPE_PF = 2, }; enum amdxdna_drm_ioctl_id { -- cgit v1.2.3 From dc2d30e7db8321a6696d266838f7af7e9d1c7155 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 27 Mar 2026 17:18:29 +0000 Subject: drm/doc: document DRM_IOCTL_SYNCOBJ_EVENTFD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct drm_syncobj_eventfd was documented, but DRM_IOCTL_SYNCOBJ_EVENTFD was not. This prevents references to this define from being properly linkified in docs. Signed-off-by: Simon Ser Reviewed-by: Christian König Reviewed-by: Pekka Paalanen Cc: Simona Vetter Cc: Daniel Stone Cc: Michel Dänzer Link: https://patch.msgid.link/20260327171812.128290-1-contact@emersion.fr --- include/uapi/drm/drm.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/uapi') diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 27cc159c1d27..495462e44a17 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1323,6 +1323,13 @@ extern "C" { */ #define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2) +/** + * DRM_IOCTL_SYNCOBJ_EVENTFD - Register an eventfd to be signalled by a syncobj. + * + * This can be used to integrate a syncobj in an event loop. + * + * The IOCTL argument is a struct drm_syncobj_eventfd. + */ #define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) /** -- cgit v1.2.3 From 3233db7682e759d101028285386ee7a11183fa2a Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:41 +0000 Subject: drm/xe/uapi: Fix typos and spelling errors in xe_drm.h documentation Fix the following typos and spelling errors in doc comments: - creaed -> created (drm_xe_query_config) - mmaping -> mmapping (drm_xe_gem_create) - 0xdeadbeaf -> 0xdeadbeef (drm_xe_gem_mmap_offset) - x2 and xe3 platform -> Xe2 and Xe3 platforms - flat -> flag (drm_xe_wait_user_fence) - MONOTONIC_CLOCK -> CLOCK_MONOTONIC (correct POSIX name) - neverending -> never ending (drm_xe_wait_user_fence) Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-2-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index ae2fda23ce7c..f17355684083 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -410,7 +410,7 @@ struct drm_xe_query_mem_regions { * device supports the userspace hint %DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION. * This is exposed only on Xe2+. * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX - Flag is set - * if a queue can be creaed with + * if a queue can be created with * %DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX * - %DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT - Minimal memory alignment * required by this device, typically SZ_4K or SZ_64K @@ -888,7 +888,7 @@ struct drm_xe_gem_create { #define DRM_XE_GEM_CPU_CACHING_WC 2 /** * @cpu_caching: The CPU caching mode to select for this object. If - * mmaping the object the mode selected here will also be used. The + * mmapping the object the mode selected here will also be used. The * exception is when mapping system memory (including data evicted * to system) on discrete GPUs. The caching mode selected will * then be overridden to DRM_XE_GEM_CPU_CACHING_WB, and coherency @@ -931,7 +931,7 @@ struct drm_xe_gem_create { * * err = ioctl(fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &mmo); * map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mmo.offset); - * map[i] = 0xdeadbeaf; // issue barrier + * map[i] = 0xdeadbeef; // issue barrier */ struct drm_xe_gem_mmap_offset { /** @extensions: Pointer to the first extension struct, if any */ @@ -958,8 +958,8 @@ struct drm_xe_gem_mmap_offset { * - %DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE - Map the whole virtual address * space of the VM to scratch page. A vm_bind would overwrite the scratch * page mapping. This flag is mutually exclusive with the - * %DRM_XE_VM_CREATE_FLAG_FAULT_MODE flag, with an exception of on x2 and - * xe3 platform. + * %DRM_XE_VM_CREATE_FLAG_FAULT_MODE flag, with an exception on Xe2 and + * Xe3 platforms. * - %DRM_XE_VM_CREATE_FLAG_LR_MODE - An LR, or Long Running VM accepts * exec submissions to its exec_queues that don't have an upper time * limit on the job execution time. But exec submissions to these @@ -1695,9 +1695,9 @@ struct drm_xe_wait_user_fence { * Without DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flag set (relative timeout) * it contains timeout expressed in nanoseconds to wait (fence will * expire at now() + timeout). - * When DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flat is set (absolute timeout) wait - * will end at timeout (uses system MONOTONIC_CLOCK). - * Passing negative timeout leads to neverending wait. + * When DRM_XE_UFENCE_WAIT_FLAG_ABSTIME flag is set (absolute timeout) wait + * will end at timeout (uses system CLOCK_MONOTONIC). + * Passing negative timeout leads to never ending wait. * * On relative timeout this value is updated with timeout left * (for restarting the call in case of signal delivery). -- cgit v1.2.3 From 65d53c13d43b8b5690c326807c1535b1d19138e8 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:42 +0000 Subject: drm/xe/uapi: Fix grammar errors in xe_drm.h documentation Fix various grammar issues in doc comments: - flag are only valid -> flag is only valid - should only ever used -> should only ever be used - if isn't already -> if it isn't already - Type of the this -> Type of this - When sync passed in -> When sync is passed in - the users responsibility -> the user's responsibility - must qword aligned -> must be qword aligned - for a observation -> for an observation - a memory ranges -> memory ranges - for each memory ranges -> for each memory range. - Second ioctl call -> second ioctl call Assisted-by: GitHub Copilot:claude-opus-4.6 Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-3-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index f17355684083..1d3406416d8c 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1045,7 +1045,7 @@ struct drm_xe_vm_destroy { * set, no mappings are created rather the range is reserved for CPU address * mirroring which will be populated on GPU page faults or prefetches. Only * valid on VMs with DRM_XE_VM_CREATE_FLAG_FAULT_MODE set. The CPU address - * mirror flag are only valid for DRM_XE_VM_BIND_OP_MAP operations, the BO + * mirror flag is only valid for DRM_XE_VM_BIND_OP_MAP operations, the BO * handle MBZ, and the BO offset MBZ. * - %DRM_XE_VM_BIND_FLAG_MADVISE_AUTORESET - Can be used in combination with * %DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR to reset madvises when the underlying @@ -1109,7 +1109,7 @@ struct drm_xe_vm_bind_op { * ppGTT WT -> COH_NONE * ppGTT WB -> COH_AT_LEAST_1WAY * - * In practice UC/WC/WT should only ever used for scanout surfaces on + * In practice UC/WC/WT should only ever be used for scanout surfaces on * such platforms (or perhaps in general for dma-buf if shared with * another device) since it is only the display engine that is actually * incoherent. Everything else should typically use WB given that we @@ -1366,7 +1366,7 @@ struct drm_xe_vm_get_property { * drm_xe_pxp_session_type. %DRM_XE_PXP_TYPE_NONE is the default behavior, so * there is no need to explicitly set that. When a queue of type * %DRM_XE_PXP_TYPE_HWDRM is created, the PXP default HWDRM session - * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if isn't already running. + * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if it isn't already running. * The user is expected to query the PXP status via the query ioctl (see * %DRM_XE_DEVICE_QUERY_PXP_STATUS) and to wait for PXP to be ready before * attempting to create a queue with this property. When a queue is created @@ -1546,7 +1546,7 @@ struct drm_xe_sync { #define DRM_XE_SYNC_TYPE_SYNCOBJ 0x0 #define DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ 0x1 #define DRM_XE_SYNC_TYPE_USER_FENCE 0x2 - /** @type: Type of the this sync object */ + /** @type: Type of this sync object */ __u32 type; #define DRM_XE_SYNC_FLAG_SIGNAL (1 << 0) @@ -1559,9 +1559,9 @@ struct drm_xe_sync { /** * @addr: Address of user fence. When sync is passed in via exec - * IOCTL this is a GPU address in the VM. When sync passed in via + * IOCTL this is a GPU address in the VM. When sync is passed in via * VM bind IOCTL this is a user pointer. In either case, it is - * the users responsibility that this address is present and + * the user's responsibility that this address is present and * mapped when the user fence is signalled. Must be qword * aligned. */ @@ -1664,7 +1664,7 @@ struct drm_xe_wait_user_fence { __u64 extensions; /** - * @addr: user pointer address to wait on, must qword aligned + * @addr: user pointer address to wait on, must be qword aligned */ __u64 addr; @@ -1769,7 +1769,7 @@ enum drm_xe_observation_ioctls { /** @DRM_XE_OBSERVATION_IOCTL_ENABLE: Enable data capture for an observation stream */ DRM_XE_OBSERVATION_IOCTL_ENABLE = _IO('i', 0x0), - /** @DRM_XE_OBSERVATION_IOCTL_DISABLE: Disable data capture for a observation stream */ + /** @DRM_XE_OBSERVATION_IOCTL_DISABLE: Disable data capture for an observation stream */ DRM_XE_OBSERVATION_IOCTL_DISABLE = _IO('i', 0x1), /** @DRM_XE_OBSERVATION_IOCTL_CONFIG: Change observation stream configuration */ @@ -2373,12 +2373,12 @@ struct drm_xe_madvise { * * This structure is provided by userspace and filled by KMD in response to the * DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS ioctl. It describes memory attributes of - * a memory ranges within a user specified address range in a VM. + * memory ranges within a user specified address range in a VM. * * The structure includes information such as atomic access policy, * page attribute table (PAT) index, and preferred memory location. * Userspace allocates an array of these structures and passes a pointer to the - * ioctl to retrieve attributes for each memory ranges + * ioctl to retrieve attributes for each memory range. * * @extensions: Pointer to the first extension struct, if any * @start: Start address of the memory range @@ -2443,7 +2443,7 @@ struct drm_xe_mem_range_attr { * If second call fails with -ENOSPC, it means memory ranges changed between * first call and now, retry IOCTL again with @num_mem_ranges = 0, * @sizeof_mem_ranges_attr = 0 and @vector_of_vma_mem_attr = NULL followed by - * Second ioctl call. + * second ioctl call. * * Example: * -- cgit v1.2.3 From ea842c235828152258fc5197212e896bc59d7b83 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:43 +0000 Subject: drm/xe/uapi: Fix wrong names and references in xe_drm.h Fix incorrect field names, struct names, ioctl names, and descriptions in doc comments: - probed_size -> @cpu_visible_size (correct field name) - @flags description was copy of @placement -> fix to reference DRM_XE_GEM_CREATE_FLAG_* - %XE_PXP_HWDRM_DEFAULT_SESSION -> %DRM_XE_PXP_HWDRM_DEFAULT_SESSION (missing DRM_ prefix) - Remove undefined %DRM_XE_UFENCE_WAIT_FLAG_SOFT_OP - &DRM_XE_OBSERVATION -> &DRM_IOCTL_XE_OBSERVATION - id's/struct's -> IDs/structs (fix incorrect possessive forms) - drm_xe_query_oa_units -> drm_xe_oa_unit - DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS -> DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS - DRM_IOCTL_XE_VM_QUERY_MEM_ATTRIBUTES -> DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS - @sizeof_mem_ranges_attr -> @sizeof_mem_range_attr - @vector_of_vma_mem_attr -> @vector_of_mem_attr v3: id -> ID. (Xin) split cross-reference fix to seperate patch. Assisted-by: GitHub Copilot:claude-opus-4.6 Cc: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-4-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 1d3406416d8c..ad8e3b69a3d7 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -349,7 +349,7 @@ struct drm_xe_mem_region { * is smaller than @total_size then this is referred to as a * small BAR system. * - * On systems without small BAR (full BAR), the probed_size will + * On systems without small BAR (full BAR), the @cpu_visible_size will * always equal the @total_size, since all of it will be CPU * accessible. * @@ -862,8 +862,7 @@ struct drm_xe_gem_create { #define DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM (1 << 2) #define DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION (1 << 3) /** - * @flags: Flags, currently a mask of memory instances of where BO can - * be placed + * @flags: Flags for the GEM object, see DRM_XE_GEM_CREATE_FLAG_* */ __u32 flags; @@ -1366,7 +1365,7 @@ struct drm_xe_vm_get_property { * drm_xe_pxp_session_type. %DRM_XE_PXP_TYPE_NONE is the default behavior, so * there is no need to explicitly set that. When a queue of type * %DRM_XE_PXP_TYPE_HWDRM is created, the PXP default HWDRM session - * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if it isn't already running. + * (%DRM_XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if it isn't already running. * The user is expected to query the PXP status via the query ioctl (see * %DRM_XE_DEVICE_QUERY_PXP_STATUS) and to wait for PXP to be ready before * attempting to create a queue with this property. When a queue is created @@ -1651,7 +1650,6 @@ struct drm_xe_exec { * * and the @flags can be: * - %DRM_XE_UFENCE_WAIT_FLAG_ABSTIME - * - %DRM_XE_UFENCE_WAIT_FLAG_SOFT_OP * * The @mask values can be for example: * - 0xffu for u8 @@ -1741,7 +1739,7 @@ enum drm_xe_observation_op { }; /** - * struct drm_xe_observation_param - Input of &DRM_XE_OBSERVATION + * struct drm_xe_observation_param - Input of &DRM_IOCTL_XE_OBSERVATION * * The observation layer enables multiplexing observation streams of * multiple types. The actual params for a particular stream operation are @@ -1902,10 +1900,10 @@ enum drm_xe_oa_format_type { }; /** - * enum drm_xe_oa_property_id - OA stream property id's + * enum drm_xe_oa_property_id - OA stream property IDs * * Stream params are specified as a chain of @drm_xe_ext_set_property - * struct's, with @property values from enum @drm_xe_oa_property_id and + * structs, with @property values from enum @drm_xe_oa_property_id and * @drm_xe_user_extension base.name set to @DRM_XE_OA_EXTENSION_SET_PROPERTY. * @param field in struct @drm_xe_observation_param points to the first * @drm_xe_ext_set_property struct. @@ -1919,7 +1917,7 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_OA_UNIT_ID: ID of the OA unit on which to open * the OA stream, see @oa_unit_id in 'struct - * drm_xe_query_oa_units'. Defaults to 0 if not provided. + * drm_xe_oa_unit'. Defaults to 0 if not provided. */ DRM_XE_OA_PROPERTY_OA_UNIT_ID = 1, @@ -2369,10 +2367,10 @@ struct drm_xe_madvise { }; /** - * struct drm_xe_mem_range_attr - Output of &DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS + * struct drm_xe_mem_range_attr - Output of &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS * * This structure is provided by userspace and filled by KMD in response to the - * DRM_IOCTL_XE_VM_QUERY_MEM_RANGES_ATTRS ioctl. It describes memory attributes of + * DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS ioctl. It describes memory attributes of * memory ranges within a user specified address range in a VM. * * The structure includes information such as atomic access policy, @@ -2427,7 +2425,7 @@ struct drm_xe_mem_range_attr { }; /** - * struct drm_xe_vm_query_mem_range_attr - Input of &DRM_IOCTL_XE_VM_QUERY_MEM_ATTRIBUTES + * struct drm_xe_vm_query_mem_range_attr - Input of &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS * * This structure is used to query memory attributes of memory regions * within a user specified address range in a VM. It provides detailed @@ -2435,14 +2433,14 @@ struct drm_xe_mem_range_attr { * page attribute table (PAT) index, and preferred memory location. * * Userspace first calls the ioctl with @num_mem_ranges = 0, - * @sizeof_mem_ranges_attr = 0 and @vector_of_vma_mem_attr = NULL to retrieve + * @sizeof_mem_range_attr = 0 and @vector_of_mem_attr = NULL to retrieve * the number of memory regions and size of each memory range attribute. * Then, it allocates a buffer of that size and calls the ioctl again to fill * the buffer with memory range attributes. * * If second call fails with -ENOSPC, it means memory ranges changed between * first call and now, retry IOCTL again with @num_mem_ranges = 0, - * @sizeof_mem_ranges_attr = 0 and @vector_of_vma_mem_attr = NULL followed by + * @sizeof_mem_range_attr = 0 and @vector_of_mem_attr = NULL followed by * second ioctl call. * * Example: -- cgit v1.2.3 From 4bd87e7c4d467ce1f9e3b56abebeffc2ba45a2fb Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:44 +0000 Subject: drm/xe/uapi: Fix kernel-doc cross-reference syntax in xe_drm.h Fix incorrect kernel-doc cross-reference markup syntax throughout xe_drm.h: - @struct_name -> &struct name for cross-references to other structs (19 occurrences) - struct @name -> &struct name where struct keyword was mixed with @ syntax (8 occurrences) - enum @name -> &enum name for cross-references to other enums (5 occurrences) - &CONSTANT / @CONSTANT -> %CONSTANT for defines and enum values (15 occurrences) - @field references to members of other structs -> plain text, since @ only applies to the current struct's members (9 occurrences) Per kernel-doc conventions (Documentation/doc-guide/kernel-doc.rst): - '&struct name' creates hyperlinks to struct definitions - '&enum name' creates hyperlinks to enum definitions - '%NAME' references constants and defines - '@name' is only for parameters/members of the current context Assisted-by: GitHub Copilot:claude-opus-4.6 Suggested-by: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-5-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 106 +++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 53 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index ad8e3b69a3d7..8751ad7b845f 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -229,9 +229,9 @@ struct drm_xe_ext_set_property { /** * struct drm_xe_engine_class_instance - instance of an engine class * - * It is returned as part of the @drm_xe_engine, but it also is used as - * the input of engine selection for both @drm_xe_exec_queue_create and - * @drm_xe_query_engine_cycles + * It is returned as part of the &struct drm_xe_engine, but it also is used as + * the input of engine selection for both &struct drm_xe_exec_queue_create and + * &struct drm_xe_query_engine_cycles * * The @engine_class can be: * - %DRM_XE_ENGINE_CLASS_RENDER @@ -264,7 +264,7 @@ struct drm_xe_engine_class_instance { * struct drm_xe_engine - describe hardware engine */ struct drm_xe_engine { - /** @instance: The @drm_xe_engine_class_instance */ + /** @instance: The &struct drm_xe_engine_class_instance */ struct drm_xe_engine_class_instance instance; /** @reserved: Reserved */ @@ -274,9 +274,9 @@ struct drm_xe_engine { /** * struct drm_xe_query_engines - describe engines * - * If a query is made with a struct @drm_xe_device_query where .query + * If a query is made with a &struct drm_xe_device_query where .query * is equal to %DRM_XE_DEVICE_QUERY_ENGINES, then the reply uses an array of - * struct @drm_xe_query_engines in .data. + * &struct drm_xe_query_engines in .data. */ struct drm_xe_query_engines { /** @num_engines: number of engines returned in @engines */ @@ -825,7 +825,7 @@ struct drm_xe_device_query { * * This ioctl supports setting the following properties via the * %DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY extension, which uses the - * generic @drm_xe_ext_set_property struct: + * generic &struct drm_xe_ext_set_property: * * - %DRM_XE_GEM_CREATE_SET_PROPERTY_PXP_TYPE - set the type of PXP session * this object will be used with. Valid values are listed in enum @@ -1198,10 +1198,10 @@ struct drm_xe_vm_bind_op { /** * struct drm_xe_vm_bind - Input of &DRM_IOCTL_XE_VM_BIND * - * Below is an example of a minimal use of @drm_xe_vm_bind to + * Below is an example of a minimal use of &struct drm_xe_vm_bind to * asynchronously bind the buffer `data` at address `BIND_ADDRESS` to * illustrate `userptr`. It can be synchronized by using the example - * provided for @drm_xe_sync. + * provided for &struct drm_xe_sync. * * .. code-block:: C * @@ -1354,7 +1354,7 @@ struct drm_xe_vm_get_property { * * This ioctl supports setting the following properties via the * %DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY extension, which uses the - * generic @drm_xe_ext_set_property struct: + * generic &struct drm_xe_ext_set_property: * * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY - set the queue priority. * CAP_SYS_NICE is required to set a value above normal. @@ -1389,9 +1389,9 @@ struct drm_xe_vm_get_property { * enable render color cache keying on BTP+BTI instead of just BTI * (only valid for render queues). * - * The example below shows how to use @drm_xe_exec_queue_create to create + * The example below shows how to use &struct drm_xe_exec_queue_create to create * a simple exec_queue (no parallel submission) of class - * &DRM_XE_ENGINE_CLASS_RENDER. + * %DRM_XE_ENGINE_CLASS_RENDER. * * .. code-block:: C * @@ -1514,7 +1514,7 @@ struct drm_xe_exec_queue_get_property { * and the @flags can be: * - %DRM_XE_SYNC_FLAG_SIGNAL * - * A minimal use of @drm_xe_sync looks like this: + * A minimal use of &struct drm_xe_sync looks like this: * * .. code-block:: C * @@ -1580,10 +1580,10 @@ struct drm_xe_sync { /** * struct drm_xe_exec - Input of &DRM_IOCTL_XE_EXEC * - * This is an example to use @drm_xe_exec for execution of the object - * at BIND_ADDRESS (see example in @drm_xe_vm_bind) by an exec_queue - * (see example in @drm_xe_exec_queue_create). It can be synchronized - * by using the example provided for @drm_xe_sync. + * This is an example to use &struct drm_xe_exec for execution of the object + * at BIND_ADDRESS (see example in &struct drm_xe_vm_bind) by an exec_queue + * (see example in &struct drm_xe_exec_queue_create). It can be synchronized + * by using the example provided for &struct drm_xe_sync. * * .. code-block:: C * @@ -1749,9 +1749,9 @@ enum drm_xe_observation_op { struct drm_xe_observation_param { /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; - /** @observation_type: observation stream type, of enum @drm_xe_observation_type */ + /** @observation_type: observation stream type, of &enum drm_xe_observation_type */ __u64 observation_type; - /** @observation_op: observation stream op, of enum @drm_xe_observation_op */ + /** @observation_op: observation stream op, of &enum drm_xe_observation_op */ __u64 observation_op; /** @param: Pointer to actual stream params */ __u64 param; @@ -1810,7 +1810,7 @@ struct drm_xe_oa_unit { /** @oa_unit_id: OA unit ID */ __u32 oa_unit_id; - /** @oa_unit_type: OA unit type of @drm_xe_oa_unit_type */ + /** @oa_unit_type: OA unit type of &enum drm_xe_oa_unit_type */ __u32 oa_unit_type; /** @capabilities: OA capabilities bit-mask */ @@ -1873,7 +1873,7 @@ struct drm_xe_query_oa_units { /** @pad: MBZ */ __u32 pad; /** - * @oa_units: struct @drm_xe_oa_unit array returned for this device. + * @oa_units: &struct drm_xe_oa_unit array returned for this device. * Written below as a u64 array to avoid problems with nested flexible * arrays with some compilers */ @@ -1902,22 +1902,22 @@ enum drm_xe_oa_format_type { /** * enum drm_xe_oa_property_id - OA stream property IDs * - * Stream params are specified as a chain of @drm_xe_ext_set_property - * structs, with @property values from enum @drm_xe_oa_property_id and - * @drm_xe_user_extension base.name set to @DRM_XE_OA_EXTENSION_SET_PROPERTY. - * @param field in struct @drm_xe_observation_param points to the first - * @drm_xe_ext_set_property struct. + * Stream params are specified as a chain of &struct drm_xe_ext_set_property + * structs, with property values from &enum drm_xe_oa_property_id and + * &struct drm_xe_user_extension base.name set to %DRM_XE_OA_EXTENSION_SET_PROPERTY. + * The param field in &struct drm_xe_observation_param points to the first + * &struct drm_xe_ext_set_property struct. * * Exactly the same mechanism is also used for stream reconfiguration using the - * @DRM_XE_OBSERVATION_IOCTL_CONFIG observation stream fd ioctl, though only a + * %DRM_XE_OBSERVATION_IOCTL_CONFIG observation stream fd ioctl, though only a * subset of properties below can be specified for stream reconfiguration. */ enum drm_xe_oa_property_id { #define DRM_XE_OA_EXTENSION_SET_PROPERTY 0 /** * @DRM_XE_OA_PROPERTY_OA_UNIT_ID: ID of the OA unit on which to open - * the OA stream, see @oa_unit_id in 'struct - * drm_xe_oa_unit'. Defaults to 0 if not provided. + * the OA stream, see oa_unit_id in &struct drm_xe_oa_unit. + * Defaults to 0 if not provided. */ DRM_XE_OA_PROPERTY_OA_UNIT_ID = 1, @@ -1930,7 +1930,7 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_OA_METRIC_SET: OA metrics defining contents of OA - * reports, previously added via @DRM_XE_OBSERVATION_OP_ADD_CONFIG. + * reports, previously added via %DRM_XE_OBSERVATION_OP_ADD_CONFIG. */ DRM_XE_OA_PROPERTY_OA_METRIC_SET, @@ -1938,7 +1938,7 @@ enum drm_xe_oa_property_id { DRM_XE_OA_PROPERTY_OA_FORMAT, /* * OA_FORMAT's are specified the same way as in PRM/Bspec 52198/60942, - * in terms of the following quantities: a. enum @drm_xe_oa_format_type + * in terms of the following quantities: a. &enum drm_xe_oa_format_type * b. Counter select c. Counter size and d. BC report. Also refer to the * oa_formats array in drivers/gpu/drm/xe/xe_oa.c. */ @@ -1955,19 +1955,19 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_OA_DISABLED: A value of 1 will open the OA - * stream in a DISABLED state (see @DRM_XE_OBSERVATION_IOCTL_ENABLE). + * stream in a DISABLED state (see %DRM_XE_OBSERVATION_IOCTL_ENABLE). */ DRM_XE_OA_PROPERTY_OA_DISABLED, /** * @DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID: Open the stream for a specific - * @exec_queue_id. OA queries can be executed on this exec queue. + * exec_queue_id. OA queries can be executed on this exec queue. */ DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID, /** * @DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE: Optional engine instance to - * pass along with @DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID or will default to 0. + * pass along with %DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID or will default to 0. */ DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE, @@ -1979,16 +1979,16 @@ enum drm_xe_oa_property_id { /** * @DRM_XE_OA_PROPERTY_NUM_SYNCS: Number of syncs in the sync array - * specified in @DRM_XE_OA_PROPERTY_SYNCS + * specified in %DRM_XE_OA_PROPERTY_SYNCS */ DRM_XE_OA_PROPERTY_NUM_SYNCS, /** - * @DRM_XE_OA_PROPERTY_SYNCS: Pointer to struct @drm_xe_sync array - * with array size specified via @DRM_XE_OA_PROPERTY_NUM_SYNCS. OA + * @DRM_XE_OA_PROPERTY_SYNCS: Pointer to &struct drm_xe_sync array + * with array size specified via %DRM_XE_OA_PROPERTY_NUM_SYNCS. OA * configuration will wait till input fences signal. Output fences * will signal after the new OA configuration takes effect. For - * @DRM_XE_SYNC_TYPE_USER_FENCE, @addr is a user pointer, similar + * %DRM_XE_SYNC_TYPE_USER_FENCE, addr is a user pointer, similar * to the VM bind case. */ DRM_XE_OA_PROPERTY_SYNCS, @@ -2011,9 +2011,9 @@ enum drm_xe_oa_property_id { /** * struct drm_xe_oa_config - OA metric configuration * - * Multiple OA configs can be added using @DRM_XE_OBSERVATION_OP_ADD_CONFIG. A + * Multiple OA configs can be added using %DRM_XE_OBSERVATION_OP_ADD_CONFIG. A * particular config can be specified when opening an OA stream using - * @DRM_XE_OA_PROPERTY_OA_METRIC_SET property. + * %DRM_XE_OA_PROPERTY_OA_METRIC_SET property. */ struct drm_xe_oa_config { /** @extensions: Pointer to the first extension struct, if any */ @@ -2034,7 +2034,7 @@ struct drm_xe_oa_config { /** * struct drm_xe_oa_stream_status - OA stream status returned from - * @DRM_XE_OBSERVATION_IOCTL_STATUS observation stream fd ioctl. Userspace can + * %DRM_XE_OBSERVATION_IOCTL_STATUS observation stream fd ioctl. Userspace can * call the ioctl to query stream status in response to EIO errno from * observation fd read(). */ @@ -2055,7 +2055,7 @@ struct drm_xe_oa_stream_status { /** * struct drm_xe_oa_stream_info - OA stream info returned from - * @DRM_XE_OBSERVATION_IOCTL_INFO observation stream fd ioctl + * %DRM_XE_OBSERVATION_IOCTL_INFO observation stream fd ioctl */ struct drm_xe_oa_stream_info { /** @extensions: Pointer to the first extension struct, if any */ @@ -2092,27 +2092,27 @@ enum drm_xe_pxp_session_type { * enum drm_xe_eu_stall_property_id - EU stall sampling input property ids. * * These properties are passed to the driver at open as a chain of - * @drm_xe_ext_set_property structures with @property set to these - * properties' enums and @value set to the corresponding values of these - * properties. @drm_xe_user_extension base.name should be set to - * @DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY. + * &struct drm_xe_ext_set_property structures with property set to these + * properties' enums and value set to the corresponding values of these + * properties. &struct drm_xe_user_extension base.name should be set to + * %DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY. * * With the file descriptor obtained from open, user space must enable - * the EU stall stream fd with @DRM_XE_OBSERVATION_IOCTL_ENABLE before + * the EU stall stream fd with %DRM_XE_OBSERVATION_IOCTL_ENABLE before * calling read(). EIO errno from read() indicates HW dropped data * due to full buffer. */ enum drm_xe_eu_stall_property_id { #define DRM_XE_EU_STALL_EXTENSION_SET_PROPERTY 0 /** - * @DRM_XE_EU_STALL_PROP_GT_ID: @gt_id of the GT on which + * @DRM_XE_EU_STALL_PROP_GT_ID: gt_id of the GT on which * EU stall data will be captured. */ DRM_XE_EU_STALL_PROP_GT_ID = 1, /** * @DRM_XE_EU_STALL_PROP_SAMPLE_RATE: Sampling rate in - * GPU cycles from @sampling_rates in struct @drm_xe_query_eu_stall + * GPU cycles from sampling_rates in &struct drm_xe_query_eu_stall */ DRM_XE_EU_STALL_PROP_SAMPLE_RATE, @@ -2127,9 +2127,9 @@ enum drm_xe_eu_stall_property_id { /** * struct drm_xe_query_eu_stall - Information about EU stall sampling. * - * If a query is made with a struct @drm_xe_device_query where .query - * is equal to @DRM_XE_DEVICE_QUERY_EU_STALL, then the reply uses - * struct @drm_xe_query_eu_stall in .data. + * If a query is made with a &struct drm_xe_device_query where .query + * is equal to %DRM_XE_DEVICE_QUERY_EU_STALL, then the reply uses + * &struct drm_xe_query_eu_stall in .data. */ struct drm_xe_query_eu_stall { /** @extensions: Pointer to the first extension struct, if any */ @@ -2240,7 +2240,7 @@ struct drm_xe_madvise { /** * @preferred_mem_loc.region_instance : Region instance. - * MBZ if @devmem_fd <= &DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE. + * MBZ if @devmem_fd <= %DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE. * Otherwise should point to the desired device * VRAM instance of the device indicated by * @preferred_mem_loc.devmem_fd. -- cgit v1.2.3 From 96cc9d79df5f7092c3807fad0d2fc3415cbd66b2 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:45 +0000 Subject: drm/xe/uapi: Fix code examples in xe_drm.h documentation Fix incorrect field names and formatting in code examples: - .num_bb_per_exec -> .width (renamed struct field in exec_queue_create examples) - .num_eng_per_bb -> .num_placements (renamed struct field in exec_queue_create examples) - .atomic_val -> .atomic.val (correct nested struct field access in madvise example) - Remove unnecessary backslash escaping in UUID format string (%\08x -> %08x) - Fix descriptive text trapped inside code-block in exec_queue_create doc (split into two code blocks) v3: one more fix of split code-block in exec_queue_create doc. Assisted-by: GitHub Copilot:claude-opus-4.6 Cc: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-6-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 8751ad7b845f..58614f62d65b 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1401,23 +1401,25 @@ struct drm_xe_vm_get_property { * struct drm_xe_exec_queue_create exec_queue_create = { * .extensions = 0, * .vm_id = vm, - * .num_bb_per_exec = 1, - * .num_eng_per_bb = 1, + * .width = 1, + * .num_placements = 1, * .instances = to_user_pointer(&instance), * }; * ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_CREATE, &exec_queue_create); * - * Allow users to provide a hint to kernel for cases demanding low latency - * profile. Please note it will have impact on power consumption. User can - * indicate low latency hint with flag while creating exec queue as - * mentioned below, + * Allow users to provide a hint to kernel for cases demanding low latency + * profile. Please note it will have impact on power consumption. User can + * indicate low latency hint with flag while creating exec queue as + * mentioned below: + * + * .. code-block:: C * * struct drm_xe_exec_queue_create exec_queue_create = { * .flags = DRM_XE_EXEC_QUEUE_LOW_LATENCY_HINT, * .extensions = 0, * .vm_id = vm, - * .num_bb_per_exec = 1, - * .num_eng_per_bb = 1, + * .width = 1, + * .num_placements = 1, * .instances = to_user_pointer(&instance), * }; * ioctl(fd, DRM_IOCTL_XE_EXEC_QUEUE_CREATE, &exec_queue_create); @@ -2019,7 +2021,7 @@ struct drm_xe_oa_config { /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; - /** @uuid: String formatted like "%\08x-%\04x-%\04x-%\04x-%\012x" */ + /** @uuid: String formatted like "%08x-%04x-%04x-%04x-%012x" */ char uuid[36]; /** @n_regs: Number of regs in @regs_ptr */ @@ -2181,7 +2183,7 @@ struct drm_xe_query_eu_stall { * .start = 0x100000, * .range = 0x2000, * .type = DRM_XE_MEM_RANGE_ATTR_ATOMIC, - * .atomic_val = DRM_XE_ATOMIC_DEVICE, + * .atomic.val = DRM_XE_ATOMIC_DEVICE, * }; * * ioctl(fd, DRM_IOCTL_XE_MADVISE, &madvise); -- cgit v1.2.3 From 5150b57dacf9563ab29661c8e8a37a73f5a9fc54 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Tue, 7 Apr 2026 03:00:46 +0000 Subject: drm/xe/uapi: Fix doc formatting and completeness in xe_drm.h - Fix missing leading space before closing */ in comment block - Add DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY to the IOCTL overview list - Add missing query types to the device query doc list: DRM_XE_DEVICE_QUERY_UC_FW_VERSION, DRM_XE_DEVICE_QUERY_OA_UNITS, DRM_XE_DEVICE_QUERY_EU_STALL - Fix ioctl's -> ioctls (not possessive, 2 occurrences) - Remove duplicate parameter docs from drm_xe_mem_range_attr overview (already documented as inline member comments) - Fix extra whitespace before /** on 2 lines in drm_xe_mem_range_attr - Add missing blank line before DRM_XE_VM_BIND_FLAG_DECOMPRESS bullet to fix RST block quote warning v3: more fix (item 4 to 7). Assisted-by: GitHub Copilot:claude-opus-4.6 Cc: Xin Wang Reviewed-by: Xin Wang Link: https://patch.msgid.link/20260407030046.3394004-7-shuicheng.lin@intel.com Signed-off-by: Shuicheng Lin --- include/uapi/drm/xe_drm.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 58614f62d65b..48e9f1fdb78d 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -83,6 +83,7 @@ extern "C" { * - &DRM_IOCTL_XE_OBSERVATION * - &DRM_IOCTL_XE_MADVISE * - &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS + * - &DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY * - &DRM_IOCTL_XE_VM_GET_PROPERTY */ @@ -167,7 +168,7 @@ extern "C" { * Typically the struct drm_xe_user_extension would be embedded in some uAPI * struct, and in this case we would feed it the head of the chain(i.e ext1), * which would then apply all of the above extensions. -*/ + */ /** * struct drm_xe_user_extension - Base class for defining a chain of extensions @@ -705,7 +706,10 @@ struct drm_xe_query_pxp_status { * attributes. * - %DRM_XE_DEVICE_QUERY_GT_TOPOLOGY * - %DRM_XE_DEVICE_QUERY_ENGINE_CYCLES + * - %DRM_XE_DEVICE_QUERY_UC_FW_VERSION + * - %DRM_XE_DEVICE_QUERY_OA_UNITS * - %DRM_XE_DEVICE_QUERY_PXP_STATUS + * - %DRM_XE_DEVICE_QUERY_EU_STALL * * If size is set to 0, the driver fills it with the required size for * the requested type of data to query. If size is equal to the required @@ -1060,6 +1064,7 @@ struct drm_xe_vm_destroy { * not invoke autoreset. Neither will stack variables going out of scope. * Therefore it's recommended to always explicitly reset the madvises when * freeing the memory backing a region used in a &DRM_IOCTL_XE_MADVISE call. + * * - %DRM_XE_VM_BIND_FLAG_DECOMPRESS - Request on-device decompression for a MAP. * When set on a MAP bind operation, request the driver schedule an on-device * in-place decompression (via the migrate/resolve path) for the GPU mapping @@ -1760,10 +1765,10 @@ struct drm_xe_observation_param { }; /** - * enum drm_xe_observation_ioctls - Observation stream fd ioctl's + * enum drm_xe_observation_ioctls - Observation stream fd ioctls * * Information exchanged between userspace and kernel for observation fd - * ioctl's is stream type specific + * ioctls is stream type specific */ enum drm_xe_observation_ioctls { /** @DRM_XE_OBSERVATION_IOCTL_ENABLE: Enable data capture for an observation stream */ @@ -2379,14 +2384,9 @@ struct drm_xe_madvise { * page attribute table (PAT) index, and preferred memory location. * Userspace allocates an array of these structures and passes a pointer to the * ioctl to retrieve attributes for each memory range. - * - * @extensions: Pointer to the first extension struct, if any - * @start: Start address of the memory range - * @end: End address of the virtual memory range - * */ struct drm_xe_mem_range_attr { - /** @extensions: Pointer to the first extension struct, if any */ + /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; /** @start: start of the memory range */ @@ -2413,7 +2413,7 @@ struct drm_xe_mem_range_attr { __u32 reserved; } atomic; - /** @pat_index: Page attribute table index */ + /** @pat_index: Page attribute table index */ struct { /** @pat_index.val: PAT index */ __u32 val; -- cgit v1.2.3 From ee18d39a087792d7c11e6e87b546aff435a3cc58 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Thu, 9 Apr 2026 13:03:19 +0530 Subject: drm/drm_ras: Add clear-error-counter netlink command to drm_ras Introduce a new 'clear-error-counter' drm_ras command to reset the counter value for a specific error counter of a given node. The command is a 'do' netlink request with 'node-id' and 'error-id' as parameters with no response payload. Usage: $ sudo ynl --family drm_ras --do clear-error-counter --json \ '{"node-id":1, "error-id":1}' None Cc: Jakub Kicinski Cc: Zack McKevitt Cc: Lijo Lazar Cc: Hawking Zhang Cc: David S. Miller Cc: Paolo Abeni Cc: Eric Dumazet Signed-off-by: Riana Tauro Reviewed-by: Jakub Kicinski Reviewed-by: Raag Jadav Link: https://patch.msgid.link/20260409073318.2909379-5-riana.tauro@intel.com Signed-off-by: Rodrigo Vivi Acked-by: Maxime Ripard --- Documentation/gpu/drm-ras.rst | 8 ++++++ Documentation/netlink/specs/drm_ras.yaml | 13 +++++++++- drivers/gpu/drm/drm_ras.c | 43 +++++++++++++++++++++++++++++++- drivers/gpu/drm/drm_ras_nl.c | 13 ++++++++++ drivers/gpu/drm/drm_ras_nl.h | 2 ++ include/drm/drm_ras.h | 11 ++++++++ include/uapi/drm/drm_ras.h | 1 + 7 files changed, 89 insertions(+), 2 deletions(-) (limited to 'include/uapi') diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst index 70b246a78fc8..4636e68f5678 100644 --- a/Documentation/gpu/drm-ras.rst +++ b/Documentation/gpu/drm-ras.rst @@ -52,6 +52,8 @@ User space tools can: as a parameter. * Query specific error counter values with the ``get-error-counter`` command, using both ``node-id`` and ``error-id`` as parameters. +* Clear specific error counters with the ``clear-error-counter`` command, using both + ``node-id`` and ``error-id`` as parameters. YAML-based Interface -------------------- @@ -101,3 +103,9 @@ Example: Query an error counter for a given node sudo ynl --family drm_ras --do get-error-counter --json '{"node-id":0, "error-id":1}' {'error-id': 1, 'error-name': 'error_name1', 'error-value': 0} +Example: Clear an error counter for a given node + +.. code-block:: bash + + sudo ynl --family drm_ras --do clear-error-counter --json '{"node-id":0, "error-id":1}' + None diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml index 79af25dac3c5..e113056f8c01 100644 --- a/Documentation/netlink/specs/drm_ras.yaml +++ b/Documentation/netlink/specs/drm_ras.yaml @@ -99,7 +99,7 @@ operations: flags: [admin-perm] do: request: - attributes: + attributes: &id-attrs - node-id - error-id reply: @@ -113,3 +113,14 @@ operations: - node-id reply: attributes: *errorinfo + - + name: clear-error-counter + doc: >- + Clear error counter for a given node. + The request includes the error-id and node-id of the + counter to be cleared. + attribute-set: error-counter-attrs + flags: [admin-perm] + do: + request: + attributes: *id-attrs diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c index b2fa5ab86d87..d6eab29a1394 100644 --- a/drivers/gpu/drm/drm_ras.c +++ b/drivers/gpu/drm/drm_ras.c @@ -26,7 +26,7 @@ * efficient lookup by ID. Nodes can be registered or unregistered * dynamically at runtime. * - * A Generic Netlink family `drm_ras` exposes two main operations to + * A Generic Netlink family `drm_ras` exposes the below operations to * userspace: * * 1. LIST_NODES: Dump all currently registered RAS nodes. @@ -37,6 +37,10 @@ * Returns all counters of a node if only Node ID is provided or specific * error counters. * + * 3. CLEAR_ERROR_COUNTER: Clear error counter of a given node. + * Userspace must provide Node ID, Error ID. + * Clears specific error counter of a node if supported. + * * Node registration: * * - drm_ras_node_register(): Registers a new node and assigns @@ -66,6 +70,8 @@ * operation, fetching all counters from a specific node. * - drm_ras_nl_get_error_counter_doit(): Implements the GET_ERROR_COUNTER doit * operation, fetching a counter value from a specific node. + * - drm_ras_nl_clear_error_counter_doit(): Implements the CLEAR_ERROR_COUNTER doit + * operation, clearing a counter value from a specific node. */ static DEFINE_XARRAY_ALLOC(drm_ras_xa); @@ -314,6 +320,41 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb, return doit_reply_value(info, node_id, error_id); } +/** + * drm_ras_nl_clear_error_counter_doit() - Clear an error counter of a node + * @skb: Netlink message buffer + * @info: Generic Netlink info containing attributes of the request + * + * Extracts the node ID and error ID from the netlink attributes and + * clears the current value. + * + * Return: 0 on success, or negative errno on failure. + */ +int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb, + struct genl_info *info) +{ + struct drm_ras_node *node; + u32 node_id, error_id; + + if (!info->attrs || + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID) || + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID)) + return -EINVAL; + + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID]); + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID]); + + node = xa_load(&drm_ras_xa, node_id); + if (!node || !node->clear_error_counter) + return -ENOENT; + + if (error_id < node->error_counter_range.first || + error_id > node->error_counter_range.last) + return -EINVAL; + + return node->clear_error_counter(node, error_id); +} + /** * drm_ras_node_register() - Register a new RAS node * @node: Node structure to register diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c index 16803d0c4a44..dea1c1b2494e 100644 --- a/drivers/gpu/drm/drm_ras_nl.c +++ b/drivers/gpu/drm/drm_ras_nl.c @@ -22,6 +22,12 @@ static const struct nla_policy drm_ras_get_error_counter_dump_nl_policy[DRM_RAS_ [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, }, }; +/* DRM_RAS_CMD_CLEAR_ERROR_COUNTER - do */ +static const struct nla_policy drm_ras_clear_error_counter_nl_policy[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID + 1] = { + [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, }, + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, }, +}; + /* Ops table for drm_ras */ static const struct genl_split_ops drm_ras_nl_ops[] = { { @@ -43,6 +49,13 @@ static const struct genl_split_ops drm_ras_nl_ops[] = { .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID, .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, }, + { + .cmd = DRM_RAS_CMD_CLEAR_ERROR_COUNTER, + .doit = drm_ras_nl_clear_error_counter_doit, + .policy = drm_ras_clear_error_counter_nl_policy, + .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, }; struct genl_family drm_ras_nl_family __ro_after_init = { diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h index 06ccd9342773..a398643572a5 100644 --- a/drivers/gpu/drm/drm_ras_nl.h +++ b/drivers/gpu/drm/drm_ras_nl.h @@ -18,6 +18,8 @@ int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb, struct genl_info *info); int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb, + struct genl_info *info); extern struct genl_family drm_ras_nl_family; diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h index 5d50209e51db..f2a787bc4f64 100644 --- a/include/drm/drm_ras.h +++ b/include/drm/drm_ras.h @@ -58,6 +58,17 @@ struct drm_ras_node { int (*query_error_counter)(struct drm_ras_node *node, u32 error_id, const char **name, u32 *val); + /** + * @clear_error_counter: + * + * This callback is used by drm_ras to clear a specific error counter. + * Driver should implement this callback to support clearing error counters + * of a node. + * + * Returns: 0 on success, negative error code on failure. + */ + int (*clear_error_counter)(struct drm_ras_node *node, u32 error_id); + /** @priv: Driver private data */ void *priv; }; diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h index 5f40fa5b869d..218a3ee86805 100644 --- a/include/uapi/drm/drm_ras.h +++ b/include/uapi/drm/drm_ras.h @@ -41,6 +41,7 @@ enum { enum { DRM_RAS_CMD_LIST_NODES = 1, DRM_RAS_CMD_GET_ERROR_COUNTER, + DRM_RAS_CMD_CLEAR_ERROR_COUNTER, __DRM_RAS_CMD_MAX, DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1) -- cgit v1.2.3 From a1b6cf8e5e7e9102f114f58e599ef1758c732efb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 7 Apr 2026 13:49:51 +0300 Subject: drm: uapi: Use SPDX in DRM core uAPI headers The DRM core uAPI headers are licensed under the MIT license, and carry copies of the license with slight variations. Replace them with SPDX headers. Following a discussion with Simona Vetter on this topic, add a clarification in the drm-uapi.rst file that independent closed-source userspace implementations of software using the DRM uAPI are accepted, as allowed by the MIT license. Signed-off-by: Laurent Pinchart Reviewed-by: Greg Kroah-Hartman Reviewed-by: Thomas Gleixner Reviewed-by: Simona Vetter Reviewed-by: Dave Airlie Link: https://patch.msgid.link/20260407104951.1781047-1-laurent.pinchart+renesas@ideasonboard.com Signed-off-by: Tomi Valkeinen --- Documentation/gpu/drm-uapi.rst | 4 ++++ include/uapi/drm/drm.h | 20 +------------------- include/uapi/drm/drm_fourcc.h | 20 +------------------- include/uapi/drm/drm_mode.h | 19 +------------------ include/uapi/drm/drm_sarea.h | 20 +------------------- 5 files changed, 8 insertions(+), 75 deletions(-) (limited to 'include/uapi') diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 579e87cb9ff7..32206ce62931 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -118,6 +118,10 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs for the same thing co-existing. If we add a few more complete mistakes into the mix every year it would be entirely unmanageable. +The DRM subsystem has however no concern with independent closed-source +userspace implementations. To officialize that position, the DRM uAPI headers +are covered by the MIT license. + .. _drm_render_node: Render nodes diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 495462e44a17..bc7ef7684099 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: MIT */ /* * Header for the Direct Rendering Manager * @@ -11,25 +12,6 @@ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _DRM_H_ diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index ac66fa93b5a3..2caf8249f892 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -1,24 +1,6 @@ +/* SPDX-License-Identifier: MIT */ /* * Copyright 2011 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef DRM_FOURCC_H diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index a4bdc4bd11bc..381a3e857d4e 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -1,27 +1,10 @@ +/* SPDX-License-Identifier: MIT */ /* * Copyright (c) 2007 Dave Airlie * Copyright (c) 2007 Jakob Bornecrantz * Copyright (c) 2008 Red Hat Inc. * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA * Copyright (c) 2007-2008 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. */ #ifndef _DRM_MODE_H diff --git a/include/uapi/drm/drm_sarea.h b/include/uapi/drm/drm_sarea.h index a951ced60ebe..1e38d028332d 100644 --- a/include/uapi/drm/drm_sarea.h +++ b/include/uapi/drm/drm_sarea.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: MIT */ /** * \file drm_sarea.h * \brief SAREA definitions @@ -8,25 +9,6 @@ /* * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _DRM_SAREA_H_ -- cgit v1.2.3 From b718f041842071b8c09faf658e3adca7b506e1bb Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 23 Apr 2026 17:21:13 +0300 Subject: drm/fourcc: Add DRM_FORMAT_P230 Add a new pixel format, DRM_FORMAT_P230 ("P230") P230 is 2 plane 10 bit per component YCbCr 2x1 subsampled format. P230 is similar to the already existing P030 format, which is 2x2 subsampled. Reviewed-by: Dmitry Baryshkov Reviewed-by: Vishal Sagar Reviewed-by: Laurent Pinchart Reviewed-by: Simon Ser Link: https://patch.msgid.link/20260423-xilinx-formats-v10-2-c690c2b8ea89@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/drm_fourcc.c | 3 +++ include/uapi/drm/drm_fourcc.h | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index e662aea9d105..5b6d8f4686c4 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -354,6 +354,9 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_P030, .depth = 0, .num_planes = 2, .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true}, + { .format = DRM_FORMAT_P230, .depth = 0, .num_planes = 2, + .char_per_block = { 4, 8, 0 }, .block_w = { 3, 3, 0 }, .block_h = { 1, 1, 0 }, + .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_S010, .depth = 0, .num_planes = 3, .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .is_yuv = true}, diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 2caf8249f892..7eb55028f35c 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -361,6 +361,14 @@ extern "C" { */ #define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */ +/* + * 2 plane YCbCr422. + * 3 10 bit components and 2 padding bits packed into 4 bytes. + * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian + * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian + */ +#define DRM_FORMAT_P230 fourcc_code('P', '2', '3', '0') /* 2x1 subsampled Cr:Cb plane 10 bits per channel packed */ + /* 3 plane non-subsampled (444) YCbCr * 16 bits per component, but only 10 bits are used and 6 bits are padded * index 0: Y plane, [15:0] Y:x [10:6] little endian -- cgit v1.2.3 From c0f8aaa7dcecee19a773a5454665998cdc848fda Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 23 Apr 2026 17:21:14 +0300 Subject: drm/fourcc: Add DRM_FORMAT_Y8 Add greyscale Y8 format. The 8-bit greyscale format has been discussed before, and the earlier guidance was to use DRM_FORMAT_R8, as a single-channel 8-bit pixel. However, adding DRM_FORMAT_Y8 makes sense, we can mark it as 'is_yuv' in the drm_format_info, and this can help the drivers handle e.g. full/limited range. This will distinguish two single-channel formats: R8, which is a RGB format with the same value for all components, and Y8, which is a Y-only YCbCr format, with Cb and Cr being neutral. Acked-by: Dmitry Baryshkov Reviewed-by: Pekka Paalanen Reviewed-by: Vishal Sagar Reviewed-by: Laurent Pinchart Acked-by: Simon Ser Link: https://patch.msgid.link/20260423-xilinx-formats-v10-3-c690c2b8ea89@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/drm_fourcc.c | 1 + include/uapi/drm/drm_fourcc.h | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 5b6d8f4686c4..c30266b8d051 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -275,6 +275,7 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_YVU422, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_YUV444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_YVU444, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_Y8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_NV12, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, { .format = DRM_FORMAT_NV21, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .is_yuv = true }, { .format = DRM_FORMAT_NV16, .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 7eb55028f35c..ede96c192169 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -441,6 +441,15 @@ extern "C" { #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ +/* + * Y-only (greyscale) formats + * + * The Y-only formats are handled similarly to the YCbCr formats in the display + * pipeline, with the Cb and Cr implicitly neutral (0.0 in nominal values). This + * also means that COLOR_RANGE property applies to the Y-only formats. + */ + +#define DRM_FORMAT_Y8 fourcc_code('G', 'R', 'E', 'Y') /* 8-bit Y-only */ /* * Format Modifiers: -- cgit v1.2.3 From e8e388c301809378f8a4789192dd965eb085dddb Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 23 Apr 2026 17:21:15 +0300 Subject: drm/fourcc: Add DRM_FORMAT_XYYY2101010 Add XYYY2101010 ("YPA4"), a 10 bit greyscale format, with 3 pixels packed into 32-bit container, and two bits of padding. The fourcc for the format is 'YPA4', which comes from Y - Y only, P - packed, A - 10 (as in 0xA), 4 - 4 bytes. Reviewed-by: Vishal Sagar Reviewed-by: Pekka Paalanen Reviewed-by: Laurent Pinchart Reviewed-by: Simon Ser Link: https://patch.msgid.link/20260423-xilinx-formats-v10-4-c690c2b8ea89@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/drm_fourcc.c | 3 +++ include/uapi/drm/drm_fourcc.h | 1 + 2 files changed, 4 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index c30266b8d051..01761c553e7e 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -385,6 +385,9 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_S416, .depth = 0, .num_planes = 3, .char_per_block = { 2, 2, 2 }, .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 1, .vsub = 1, .is_yuv = true}, + { .format = DRM_FORMAT_XYYY2101010, .depth = 0, .num_planes = 1, + .char_per_block = { 4, 0, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 }, + .hsub = 1, .vsub = 1, .is_yuv = true }, }; unsigned int i; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index ede96c192169..480c67296d6a 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -450,6 +450,7 @@ extern "C" { */ #define DRM_FORMAT_Y8 fourcc_code('G', 'R', 'E', 'Y') /* 8-bit Y-only */ +#define DRM_FORMAT_XYYY2101010 fourcc_code('Y', 'P', 'A', '4') /* [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian */ /* * Format Modifiers: -- cgit v1.2.3 From 7db42b1718dac7aa67ec68acad177164516af71d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 23 Apr 2026 17:21:16 +0300 Subject: drm/fourcc: Add DRM_FORMAT_T430 Add T430, a 3 plane 10 bits per component non-subsampled YCbCr format. A new initial letter was chosen for this one, as the format doesn't match the existing P, Q or S formats. T is the next one in the alphabet. It was definitely not chosen because of the initial letter in the author's name. Reviewed-by: Dmitry Baryshkov Reviewed-by: Vishal Sagar Reviewed-by: Laurent Pinchart Reviewed-by: Simon Ser Link: https://patch.msgid.link/20260423-xilinx-formats-v10-5-c690c2b8ea89@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/drm_fourcc.c | 3 +++ include/uapi/drm/drm_fourcc.h | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 01761c553e7e..20b84efc135e 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -388,6 +388,9 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_XYYY2101010, .depth = 0, .num_planes = 1, .char_per_block = { 4, 0, 0 }, .block_w = { 3, 0, 0 }, .block_h = { 1, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_T430, .depth = 0, .num_planes = 3, + .char_per_block = { 4, 4, 4 }, .block_w = { 3, 3, 3 }, .block_h = { 1, 1, 1 }, + .hsub = 1, .vsub = 1, .is_yuv = true }, }; unsigned int i; diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 480c67296d6a..250b0b00ed88 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -385,6 +385,15 @@ extern "C" { */ #define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') +/* + * 3 plane non-subsampled (444) YCbCr LSB aligned + * 10 bpc, 30 bits per sample image data in a single contiguous buffer. + * index 0: Y plane, [31:0] x:Y2:Y1:Y0 [2:10:10:10] little endian + * index 1: Cb plane, [31:0] x:Cb2:Cb1:Cb0 [2:10:10:10] little endian + * index 2: Cr plane, [31:0] x:Cr2:Cr1:Cr0 [2:10:10:10] little endian + */ +#define DRM_FORMAT_T430 fourcc_code('T', '4', '3', '0') + /* * 3 plane YCbCr LSB aligned * In order to use these formats in a similar fashion to MSB aligned ones -- cgit v1.2.3 From 3c8ed384503f42b985b48310fbe611418b3d5370 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 23 Apr 2026 17:21:17 +0300 Subject: drm/fourcc: Add DRM_FORMAT_XVUY2101010 Add XVUY2101010, a 10 bits per component YCbCr format in a 32 bit container. Reviewed-by: Laurent Pinchart Reviewed-by: Vishal Sagar Reviewed-by: Simon Ser Link: https://patch.msgid.link/20260423-xilinx-formats-v10-6-c690c2b8ea89@ideasonboard.com Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/drm_fourcc.c | 1 + include/uapi/drm/drm_fourcc.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 20b84efc135e..60cd02b7ea64 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -288,6 +288,7 @@ const struct drm_format_info *__drm_format_info(u32 format) { .format = DRM_FORMAT_VYUY, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_XYUV8888, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_VUY888, .depth = 0, .num_planes = 1, .cpp = { 3, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, + { .format = DRM_FORMAT_XVUY2101010, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_AYUV, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1, .has_alpha = true, .is_yuv = true }, { .format = DRM_FORMAT_Y210, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, { .format = DRM_FORMAT_Y212, .depth = 0, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 2, .vsub = 1, .is_yuv = true }, diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 250b0b00ed88..15aa0a8f44b0 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -246,6 +246,7 @@ extern "C" { #define DRM_FORMAT_XVUY8888 fourcc_code('X', 'V', 'U', 'Y') /* [31:0] X:Cr:Cb:Y 8:8:8:8 little endian */ #define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */ #define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */ +#define DRM_FORMAT_XVUY2101010 fourcc_code('X', 'Y', '3', '0') /* [31:0] x:Cr:Cb:Y 2:10:10:10 little endian */ /* * packed Y2xx indicate for each component, xx valid data occupy msb -- cgit v1.2.3 From 7b1a245b180579a844e506193f1f714edaf24bc1 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Tue, 5 May 2026 09:09:31 -0700 Subject: accel/amdxdna: Add initial support for AIE4 VF Add basic device initialization support for AIE4 Virtual Functions (PCI device IDs 0x17F3 and 0x1B0C). Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260505160936.3917732-2-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie4_pci.c | 160 +++++++++++++++++--------------- drivers/accel/amdxdna/aie4_pci.h | 3 +- drivers/accel/amdxdna/amdxdna_pci_drv.c | 4 + drivers/accel/amdxdna/amdxdna_pci_drv.h | 1 + drivers/accel/amdxdna/npu3_regs.c | 20 +++- include/uapi/drm/amdxdna_accel.h | 1 + 6 files changed, 113 insertions(+), 76 deletions(-) (limited to 'include/uapi') diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c index 87f80f804f91..a967e2db7ebd 100644 --- a/drivers/accel/amdxdna/aie4_pci.c +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -196,8 +196,9 @@ free_channel: return ret; } -static int aie4_mailbox_init(struct amdxdna_dev *xdna) +static int aie4_mailbox_init(struct amdxdna_dev_hdl *ndev) { + struct amdxdna_dev *xdna = ndev->aie.xdna; struct mailbox_info mbox_info; int ret; @@ -208,13 +209,13 @@ static int aie4_mailbox_init(struct amdxdna_dev *xdna) return aie4_mailbox_start(xdna, &mbox_info); } -static void aie4_fw_unload(struct amdxdna_dev_hdl *ndev) +static void aie4_fw_stop(struct amdxdna_dev_hdl *ndev) { aie_psp_stop(ndev->aie.psp_hdl); aie_smu_fini(ndev->aie.smu_hdl); } -static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) +static int aie4_fw_start(struct amdxdna_dev_hdl *ndev) { int ret; @@ -233,49 +234,49 @@ static int aie4_fw_load(struct amdxdna_dev_hdl *ndev) return ret; } -static int aie4_hw_start(struct amdxdna_dev *xdna) +static int aie4_pf_hw_start(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev_hdl *ndev = xdna->dev_handle; int ret; - ret = aie4_fw_load(ndev); + ret = aie4_fw_start(ndev); if (ret) return ret; - ret = aie4_mailbox_init(xdna); + ret = aie4_mailbox_init(ndev); if (ret) - goto fw_unload; + goto stop_fw; return 0; -fw_unload: - aie4_fw_unload(ndev); +stop_fw: + aie4_fw_stop(ndev); return ret; } -static void aie4_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev) +static void aie4_pf_hw_stop(struct amdxdna_dev_hdl *ndev) { - int ret; + struct amdxdna_dev *xdna = ndev->aie.xdna; - /* No paired resume needed, fw is stateless */ - ret = aie4_suspend_fw(ndev); - if (ret) - XDNA_ERR(ndev->aie.xdna, "suspend_fw failed, ret %d", ret); - else - XDNA_DBG(ndev->aie.xdna, "npu firmware suspended"); + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + aie4_suspend_fw(ndev); + aie4_mailbox_fini(ndev); + aie4_fw_stop(ndev); } -static void aie4_hw_stop(struct amdxdna_dev *xdna) +static int aie4_vf_hw_start(struct amdxdna_dev_hdl *ndev) { - struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + return aie4_mailbox_init(ndev); +} + +static void aie4_vf_hw_stop(struct amdxdna_dev_hdl *ndev) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); - aie4_mgmt_fw_fini(ndev); aie4_mailbox_fini(ndev); - - aie4_fw_unload(ndev); } static int aie4_request_firmware(struct amdxdna_dev_hdl *ndev, @@ -365,15 +366,41 @@ static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev, return 0; } -static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) +static int aie4_load_fw(struct amdxdna_dev_hdl *ndev, + void __iomem *tbl[PCI_NUM_RESOURCES]) +{ + const struct firmware *npufw, *certfw; + int ret; + + if (!ndev->priv->npufw_path && !ndev->priv->certfw_path) + return 0; + + ret = aie4_request_firmware(ndev, &npufw, &certfw); + if (ret) + return ret; + + ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl); + aie4_release_firmware(ndev, npufw, certfw); + + return ret; +} + +static int aie4m_pcidev_init(struct amdxdna_dev *xdna) { - struct amdxdna_dev *xdna = ndev->aie.xdna; struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + struct amdxdna_dev_hdl *ndev; void __iomem *tbl[PCI_NUM_RESOURCES] = {0}; - const struct firmware *npufw, *certfw; unsigned long bars = 0; int ret, i; + ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); + if (!ndev) + return -ENOMEM; + + ndev->priv = xdna->dev_info->dev_priv; + ndev->aie.xdna = xdna; + xdna->dev_handle = ndev; + /* Enable managed PCI device */ ret = pcim_enable_device(pdev); if (ret) { @@ -409,75 +436,60 @@ static int aie4_pcidev_init(struct amdxdna_dev_hdl *ndev) pci_set_master(pdev); - ret = aie4_request_firmware(ndev, &npufw, &certfw); - if (ret) - goto clear_master; - - ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl); - aie4_release_firmware(ndev, npufw, certfw); + ret = aie4_load_fw(ndev, tbl); if (ret) - goto clear_master; + return ret; ret = aie4_irq_init(xdna); if (ret) - goto clear_master; + return ret; - ret = aie4_hw_start(xdna); - if (ret) - goto clear_master; + amdxdna_vbnv_init(xdna); + XDNA_DBG(xdna, "init finished"); return 0; - -clear_master: - pci_clear_master(pdev); - - return ret; } -static void aie4_pcidev_fini(struct amdxdna_dev_hdl *ndev) +static int aie4_pf_init(struct amdxdna_dev *xdna) { - struct amdxdna_dev *xdna = ndev->aie.xdna; - struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); - - aie4_hw_stop(xdna); - - pci_clear_master(pdev); -} + int ret; -static void aie4_fini(struct amdxdna_dev *xdna) -{ - struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + ret = aie4m_pcidev_init(xdna); + if (ret) + return ret; - aie4_sriov_stop(ndev); - aie4_pcidev_fini(ndev); + return aie4_pf_hw_start(xdna->dev_handle); } -static int aie4_init(struct amdxdna_dev *xdna) +static int aie4_vf_init(struct amdxdna_dev *xdna) { - struct amdxdna_dev_hdl *ndev; int ret; - ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); - if (!ndev) - return -ENOMEM; + ret = aie4m_pcidev_init(xdna); + if (ret) + return ret; - ndev->priv = xdna->dev_info->dev_priv; - ndev->aie.xdna = xdna; - xdna->dev_handle = ndev; + return aie4_vf_hw_start(xdna->dev_handle); +} - ret = aie4_pcidev_init(ndev); - if (ret) { - XDNA_ERR(xdna, "Setup PCI device failed, ret %d", ret); - return ret; - } +static void aie4_pf_fini(struct amdxdna_dev *xdna) +{ + aie4_sriov_stop(xdna->dev_handle); + aie4_pf_hw_stop(xdna->dev_handle); +} - amdxdna_vbnv_init(xdna); - XDNA_DBG(xdna, "aie4 init finished"); - return 0; +static void aie4_vf_fini(struct amdxdna_dev *xdna) +{ + aie4_vf_hw_stop(xdna->dev_handle); } -const struct amdxdna_dev_ops aie4_ops = { - .init = aie4_init, - .fini = aie4_fini, +const struct amdxdna_dev_ops aie4_pf_ops = { + .init = aie4_pf_init, + .fini = aie4_pf_fini, .sriov_configure = aie4_sriov_configure, }; + +const struct amdxdna_dev_ops aie4_vf_ops = { + .init = aie4_vf_init, + .fini = aie4_vf_fini, +}; diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h index aa1495c3370b..cbf3424a4341 100644 --- a/drivers/accel/amdxdna/aie4_pci.h +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -48,6 +48,7 @@ static inline int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev) } #endif -extern const struct amdxdna_dev_ops aie4_ops; +extern const struct amdxdna_dev_ops aie4_pf_ops; +extern const struct amdxdna_dev_ops aie4_vf_ops; #endif /* _AIE4_PCI_H_ */ diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 1b08a08343cf..39ad081ac082 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -53,7 +53,9 @@ static const struct pci_device_id pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1502) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f0) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f2) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x17f3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1B0B) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1B0C) }, {0} }; @@ -65,7 +67,9 @@ static const struct amdxdna_device_id amdxdna_ids[] = { { 0x17f0, 0x11, &dev_npu5_info }, { 0x17f0, 0x20, &dev_npu6_info }, { 0x17f2, 0x10, &dev_npu3_pf_info }, + { 0x17f3, 0x10, &dev_npu3_vf_info }, { 0x1B0B, 0x10, &dev_npu3_pf_info }, + { 0x1B0C, 0x10, &dev_npu3_vf_info }, {0} }; diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index b1548cf16f59..caed11c09e55 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -167,6 +167,7 @@ struct amdxdna_client { /* Add device info below */ extern const struct amdxdna_dev_info dev_npu1_info; extern const struct amdxdna_dev_info dev_npu3_pf_info; +extern const struct amdxdna_dev_info dev_npu3_vf_info; extern const struct amdxdna_dev_info dev_npu4_info; extern const struct amdxdna_dev_info dev_npu5_info; extern const struct amdxdna_dev_info dev_npu6_info; diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c index acece0faddf2..6d5da779232b 100644 --- a/drivers/accel/amdxdna/npu3_regs.c +++ b/drivers/accel/amdxdna/npu3_regs.c @@ -64,6 +64,14 @@ static const struct amdxdna_dev_priv npu3_dev_priv = { }, }; +static const struct amdxdna_dev_priv npu3_dev_vf_priv = { + /* vf device does not load firmware */ + .mbox_bar = NPU3_MBOX_BAR, + .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR, + .mbox_info_off = NPU3_MBOX_INFO_OFF, + /* vf device does not have smu and psp */ +}; + const struct amdxdna_dev_info dev_npu3_pf_info = { .mbox_bar = NPU3_MBOX_BAR, .sram_bar = NPU3_MBOX_BUFFER_BAR, @@ -73,5 +81,15 @@ const struct amdxdna_dev_info dev_npu3_pf_info = { .device_type = AMDXDNA_DEV_TYPE_PF, .dev_priv = &npu3_dev_priv, .fw_feature_tbl = npu3_fw_feature_table, - .ops = &aie4_ops, + .ops = &aie4_pf_ops, +}; + +const struct amdxdna_dev_info dev_npu3_vf_info = { + .mbox_bar = NPU3_MBOX_BAR, + .sram_bar = NPU3_MBOX_BUFFER_BAR, + .default_vbnv = "RyzenAI-npu3-vf", + .device_type = AMDXDNA_DEV_TYPE_UMQ, + .dev_priv = &npu3_dev_vf_priv, + .fw_feature_tbl = npu3_fw_feature_table, + .ops = &aie4_vf_ops, }; diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h index 0b11e8e3ea5d..34212feee15c 100644 --- a/include/uapi/drm/amdxdna_accel.h +++ b/include/uapi/drm/amdxdna_accel.h @@ -30,6 +30,7 @@ extern "C" { enum amdxdna_device_type { AMDXDNA_DEV_TYPE_UNKNOWN = -1, AMDXDNA_DEV_TYPE_KMQ = 0, + AMDXDNA_DEV_TYPE_UMQ = 1, AMDXDNA_DEV_TYPE_PF = 2, }; -- cgit v1.2.3 From 193612791eea3648e6647ad74cacb191f9d0ef33 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Tue, 5 May 2026 09:09:33 -0700 Subject: accel/amdxdna: Add AIE4 VF hardware context create and destroy Implement hardware context creation and destruction for AIE4 VF devices. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260505160936.3917732-4-lizhi.hou@amd.com --- drivers/accel/amdxdna/Makefile | 1 + drivers/accel/amdxdna/aie4_ctx.c | 258 ++++++++++++++++++++++++++++++++ drivers/accel/amdxdna/aie4_host_queue.h | 22 +++ drivers/accel/amdxdna/aie4_msg_priv.h | 29 ++++ drivers/accel/amdxdna/aie4_pci.c | 5 + drivers/accel/amdxdna/aie4_pci.h | 24 +++ drivers/accel/amdxdna/amdxdna_ctx.c | 6 + drivers/accel/amdxdna/amdxdna_ctx.h | 3 + include/uapi/drm/amdxdna_accel.h | 1 + 9 files changed, 349 insertions(+) create mode 100644 drivers/accel/amdxdna/aie4_ctx.c create mode 100644 drivers/accel/amdxdna/aie4_host_queue.h (limited to 'include/uapi') diff --git a/drivers/accel/amdxdna/Makefile b/drivers/accel/amdxdna/Makefile index d7720c8c8a98..05cce0a38692 100644 --- a/drivers/accel/amdxdna/Makefile +++ b/drivers/accel/amdxdna/Makefile @@ -10,6 +10,7 @@ amdxdna-y := \ aie2_pci.o \ aie2_pm.o \ aie2_solver.o \ + aie4_ctx.o \ aie4_message.o \ aie4_pci.o \ amdxdna_cbuf.o \ diff --git a/drivers/accel/amdxdna/aie4_ctx.c b/drivers/accel/amdxdna/aie4_ctx.c new file mode 100644 index 000000000000..84ac706d0ffb --- /dev/null +++ b/drivers/accel/amdxdna/aie4_ctx.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "aie.h" +#include "aie4_host_queue.h" +#include "aie4_msg_priv.h" +#include "aie4_pci.h" +#include "amdxdna_ctx.h" +#include "amdxdna_gem.h" +#include "amdxdna_mailbox.h" +#include "amdxdna_mailbox_helper.h" +#include "amdxdna_pci_drv.h" + +static irqreturn_t cert_comp_isr(int irq, void *p) +{ + struct cert_comp *cert_comp = p; + + wake_up_all(&cert_comp->waitq); + return IRQ_HANDLED; +} + +static struct cert_comp *aie4_lookup_cert_comp(struct amdxdna_dev_hdl *ndev, u32 msix_idx) +{ + struct amdxdna_dev *xdna = ndev->aie.xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + struct cert_comp *cert_comp; + int ret; + + guard(mutex)(&ndev->cert_comp_lock); + + cert_comp = xa_load(&ndev->cert_comp_xa, msix_idx); + if (cert_comp) { + kref_get(&cert_comp->kref); + return cert_comp; + } + + cert_comp = kzalloc_obj(*cert_comp); + if (!cert_comp) + return NULL; + + cert_comp->ndev = ndev; + cert_comp->msix_idx = msix_idx; + init_waitqueue_head(&cert_comp->waitq); + kref_init(&cert_comp->kref); + + ret = pci_irq_vector(pdev, cert_comp->msix_idx); + if (ret < 0) { + XDNA_ERR(xdna, "MSI-X idx %u is invalid, ret:%d", msix_idx, ret); + goto free_cert_comp; + } + cert_comp->irq = ret; + + ret = request_irq(cert_comp->irq, cert_comp_isr, 0, "xdna_hsa", cert_comp); + if (ret) { + XDNA_ERR(xdna, "request irq %d failed %d", cert_comp->irq, ret); + goto free_cert_comp; + } + + ret = xa_err(xa_store(&ndev->cert_comp_xa, msix_idx, cert_comp, GFP_KERNEL)); + if (ret) { + XDNA_ERR(xdna, "store cert_comp for msix idx %d failed %d", msix_idx, ret); + goto free_irq; + } + + return cert_comp; + +free_irq: + free_irq(cert_comp->irq, cert_comp); +free_cert_comp: + kfree(cert_comp); + return NULL; +} + +static void cert_comp_release(struct kref *kref) +{ + struct cert_comp *cert_comp = container_of(kref, struct cert_comp, kref); + struct amdxdna_dev_hdl *ndev = cert_comp->ndev; + + drm_WARN_ON(&ndev->aie.xdna->ddev, !mutex_is_locked(&ndev->cert_comp_lock)); + + xa_erase(&ndev->cert_comp_xa, cert_comp->msix_idx); + free_irq(cert_comp->irq, cert_comp); + kfree(cert_comp); +} + +static void aie4_put_cert_comp(struct cert_comp *cert_comp) +{ + struct amdxdna_dev_hdl *ndev; + + ndev = cert_comp->ndev; + guard(mutex)(&ndev->cert_comp_lock); + kref_put(&cert_comp->kref, cert_comp_release); +} + +static int aie4_msg_destroy_context(struct amdxdna_dev_hdl *ndev, u32 hw_context_id) +{ + DECLARE_AIE_MSG(aie4_msg_destroy_hw_context, AIE4_MSG_OP_DESTROY_HW_CONTEXT); + + req.hw_context_id = hw_context_id; + return aie_send_mgmt_msg_wait(&ndev->aie, &msg); +} + +static int aie4_hwctx_create(struct amdxdna_hwctx *hwctx) +{ + DECLARE_AIE_MSG(aie4_msg_create_hw_context, AIE4_MSG_OP_CREATE_HW_CONTEXT); + struct amdxdna_client *client = hwctx->client; + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct amdxdna_dev *xdna = hwctx->client->xdna; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + int ret; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + if (!ndev->partition_id || !hwctx->num_tiles) { + XDNA_ERR(xdna, "invalid request partition_id %d, num_tiles %d", + ndev->partition_id, hwctx->num_tiles); + return -EINVAL; + } + + req.partition_id = ndev->partition_id; + req.request_num_tiles = hwctx->num_tiles; + req.pasid = FIELD_PREP(AIE4_MSG_PASID, client->pasid) | + FIELD_PREP(AIE4_MSG_PASID_VLD, 1); + req.priority_band = hwctx->qos.priority; + + req.hsa_addr_high = upper_32_bits(amdxdna_gem_dev_addr(priv->umq_bo)); + req.hsa_addr_low = lower_32_bits(amdxdna_gem_dev_addr(priv->umq_bo)); + + XDNA_DBG(xdna, "pasid 0x%x, num_tiles %d, hsa[0x%x 0x%x]", + req.pasid, req.request_num_tiles, req.hsa_addr_high, req.hsa_addr_low); + + ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg); + if (ret) { + XDNA_ERR(xdna, "create ctx failed: %d", ret); + return ret; + } + + XDNA_DBG(xdna, "resp msix: %d, ctx id: %d, doorbell: %d", + resp.job_complete_msix_idx, + resp.hw_context_id, + resp.doorbell_offset); + + /* setup interrupt completion per msix index */ + priv->cert_comp = aie4_lookup_cert_comp(ndev, resp.job_complete_msix_idx); + if (!priv->cert_comp) { + aie4_msg_destroy_context(ndev, resp.hw_context_id); + return -EINVAL; + } + + priv->hw_ctx_id = resp.hw_context_id; + hwctx->doorbell_offset = resp.doorbell_offset; + + return 0; +} + +static void aie4_hwctx_destroy(struct amdxdna_hwctx *hwctx) +{ + struct amdxdna_client *client = hwctx->client; + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct amdxdna_dev *xdna = client->xdna; + struct amdxdna_dev_hdl *ndev = xdna->dev_handle; + + drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); + + aie4_msg_destroy_context(ndev, priv->hw_ctx_id); + aie4_put_cert_comp(priv->cert_comp); +} + +static void aie4_hwctx_umq_fini(struct amdxdna_hwctx *hwctx) +{ + if (hwctx->priv && hwctx->priv->umq_bo) + amdxdna_gem_put_obj(hwctx->priv->umq_bo); +} + +static int aie4_hwctx_umq_init(struct amdxdna_hwctx *hwctx) +{ + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct amdxdna_dev *xdna = hwctx->client->xdna; + struct amdxdna_gem_obj *umq_bo; + struct host_queue_header *qhdr; + int ret; + + umq_bo = amdxdna_gem_get_obj(hwctx->client, hwctx->umq_bo_hdl, AMDXDNA_BO_SHARE); + if (!umq_bo) { + XDNA_ERR(xdna, "cannot find umq_bo handle %d", hwctx->umq_bo_hdl); + return -ENOENT; + } + if (umq_bo->mem.size < sizeof(*qhdr)) { + XDNA_ERR(xdna, "umq_bo size is too small"); + ret = -EINVAL; + goto put_umq_bo; + } + + /* get kva address for host queue read index and write index */ + qhdr = amdxdna_gem_vmap(umq_bo); + if (!qhdr) { + ret = -ENOMEM; + goto put_umq_bo; + } + + priv->umq_bo = umq_bo; + priv->umq_read_index = &qhdr->read_index; + priv->umq_write_index = &qhdr->write_index; + + return 0; + +put_umq_bo: + amdxdna_gem_put_obj(umq_bo); + return ret; +} + +int aie4_hwctx_init(struct amdxdna_hwctx *hwctx) +{ + struct amdxdna_client *client = hwctx->client; + struct amdxdna_dev *xdna = client->xdna; + struct amdxdna_hwctx_priv *priv; + int ret; + + priv = kzalloc_obj(*priv); + if (!priv) + return -ENOMEM; + hwctx->priv = priv; + + ret = aie4_hwctx_umq_init(hwctx); + if (ret) + goto free_priv; + + ret = aie4_hwctx_create(hwctx); + if (ret) + goto umq_fini; + + XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name); + return 0; + +umq_fini: + aie4_hwctx_umq_fini(hwctx); +free_priv: + kfree(priv); + hwctx->priv = NULL; + return ret; +} + +void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx) +{ + aie4_hwctx_destroy(hwctx); + aie4_hwctx_umq_fini(hwctx); + kfree(hwctx->priv); +} diff --git a/drivers/accel/amdxdna/aie4_host_queue.h b/drivers/accel/amdxdna/aie4_host_queue.h new file mode 100644 index 000000000000..eb6a38dfb53e --- /dev/null +++ b/drivers/accel/amdxdna/aie4_host_queue.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#ifndef _AIE4_HOST_QUEUE_H_ +#define _AIE4_HOST_QUEUE_H_ + +#include + +struct host_queue_header { + __u64 read_index; + struct { + __u16 major; + __u16 minor; + } version; + __u32 capacity; /* Queue capacity, must be power of two. */ + __u64 write_index; + __u64 data_address; /* The xdna dev addr for payload. */ +}; + +#endif /* _AIE4_HOST_QUEUE_H_ */ diff --git a/drivers/accel/amdxdna/aie4_msg_priv.h b/drivers/accel/amdxdna/aie4_msg_priv.h index cada53257921..7faa01ca3436 100644 --- a/drivers/accel/amdxdna/aie4_msg_priv.h +++ b/drivers/accel/amdxdna/aie4_msg_priv.h @@ -16,6 +16,8 @@ enum aie4_msg_opcode { AIE4_MSG_OP_CREATE_PARTITION = 0x30001, AIE4_MSG_OP_DESTROY_PARTITION = 0x30002, + AIE4_MSG_OP_CREATE_HW_CONTEXT = 0x30003, + AIE4_MSG_OP_DESTROY_HW_CONTEXT = 0x30004, }; enum aie4_msg_status { @@ -67,4 +69,31 @@ struct aie4_msg_destroy_partition_resp { enum aie4_msg_status status; } __packed; +struct aie4_msg_create_hw_context_req { + __u32 partition_id; + __u32 request_num_tiles; + __u32 hsa_addr_high; + __u32 hsa_addr_low; +#define AIE4_MSG_PASID GENMASK(19, 0) +#define AIE4_MSG_PASID_VLD GENMASK(31, 31) + __u32 pasid; + __u32 priority_band; +} __packed; + +struct aie4_msg_create_hw_context_resp { + enum aie4_msg_status status; + __u32 hw_context_id; + __u32 doorbell_offset; + __u32 job_complete_msix_idx; +} __packed; + +struct aie4_msg_destroy_hw_context_req { + __u32 hw_context_id; + __u32 resvd1; +} __packed; + +struct aie4_msg_destroy_hw_context_resp { + enum aie4_msg_status status; +} __packed; + #endif /* _AIE4_MSG_PRIV_H_ */ diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c index 13f5d45e388d..3be9066b7178 100644 --- a/drivers/accel/amdxdna/aie4_pci.c +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -451,6 +451,9 @@ static int aie4m_pcidev_init(struct amdxdna_dev *xdna) ndev->aie.xdna = xdna; xdna->dev_handle = ndev; + xa_init_flags(&ndev->cert_comp_xa, XA_FLAGS_ALLOC); + mutex_init(&ndev->cert_comp_lock); + /* Enable managed PCI device */ ret = pcim_enable_device(pdev); if (ret) { @@ -542,4 +545,6 @@ const struct amdxdna_dev_ops aie4_pf_ops = { const struct amdxdna_dev_ops aie4_vf_ops = { .init = aie4_vf_init, .fini = aie4_vf_fini, + .hwctx_init = aie4_hwctx_init, + .hwctx_fini = aie4_hwctx_fini, }; diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h index 620fb5bd23e4..6103007e6d2f 100644 --- a/drivers/accel/amdxdna/aie4_pci.h +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -13,6 +13,23 @@ #include "aie.h" #include "amdxdna_mailbox.h" +struct cert_comp { + struct amdxdna_dev_hdl *ndev; + u32 msix_idx; + int irq; + struct kref kref; + wait_queue_head_t waitq; +}; + +struct amdxdna_hwctx_priv { + struct amdxdna_gem_obj *umq_bo; + u64 *umq_read_index; + u64 *umq_write_index; + + struct cert_comp *cert_comp; + u32 hw_ctx_id; +}; + struct amdxdna_dev_priv { const char *npufw_path; const char *certfw_path; @@ -32,11 +49,18 @@ struct amdxdna_dev_hdl { struct mailbox *mbox; u32 partition_id; + + struct xarray cert_comp_xa; /* device level indexed by msix id */ + struct mutex cert_comp_lock; /* protects cert_comp operations*/ }; /* aie4_message.c */ int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev); +/* aie4_ctx.c */ +int aie4_hwctx_init(struct amdxdna_hwctx *hwctx); +void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx); + /* aie4_sriov.c */ #if IS_ENABLED(CONFIG_PCI_IOV) int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs); diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index 2c2c21992c87..b5ad60d4b734 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -207,6 +207,9 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr if (args->ext || args->ext_flags) return -EINVAL; + if (!xdna->dev_info->ops->hwctx_init) + return -EOPNOTSUPP; + hwctx = kzalloc_obj(*hwctx); if (!hwctx) return -ENOMEM; @@ -220,6 +223,8 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr hwctx->client = client; hwctx->fw_ctx_id = -1; hwctx->num_tiles = args->num_tiles; + hwctx->umq_bo_hdl = args->umq_bo; + hwctx->doorbell_offset = AMDXDNA_INVALID_DOORBELL_OFFSET; hwctx->mem_size = args->mem_size; hwctx->max_opc = args->max_opc; @@ -252,6 +257,7 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr args->handle = hwctx->id; args->syncobj_handle = hwctx->syncobj_hdl; + args->umq_doorbell = hwctx->doorbell_offset; atomic64_set(&hwctx->job_submit_cnt, 0); atomic64_set(&hwctx->job_free_cnt, 0); diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index 355798687376..c5622718b4d5 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -14,6 +14,7 @@ struct amdxdna_hwctx_priv; enum ert_cmd_opcode { ERT_START_CU = 0, + ERT_START_DPU = 18, ERT_CMD_CHAIN = 19, ERT_START_NPU = 20, ERT_START_NPU_PREEMPT = 21, @@ -105,6 +106,8 @@ struct amdxdna_hwctx { u32 *col_list; u32 start_col; u32 num_col; + u32 umq_bo_hdl; + u32 doorbell_offset; u32 num_unused_col; struct amdxdna_qos_info qos; diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h index 34212feee15c..ad9b33dd7b13 100644 --- a/include/uapi/drm/amdxdna_accel.h +++ b/include/uapi/drm/amdxdna_accel.h @@ -18,6 +18,7 @@ extern "C" { #define AMDXDNA_INVALID_CTX_HANDLE 0 #define AMDXDNA_INVALID_BO_HANDLE 0 #define AMDXDNA_INVALID_FENCE_HANDLE 0 +#define AMDXDNA_INVALID_DOORBELL_OFFSET (~0U) /* * Define hardware context priority -- cgit v1.2.3 From 91f4da826c082f7dca4a1f90fa3f032255f69c18 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Tue, 5 May 2026 09:09:34 -0700 Subject: accel/amdxdna: Add command doorbell and wait support Expose the command doorbell register to userspace on a per-hardware context basis, enabling applications to notify the firmware of pending commands via doorbell writes. Introduce DRM_IOCTL_AMDXDNA_WAIT_CMD to allow userspace to wait for completion of individual commands. Co-developed-by: Hayden Laccabue Signed-off-by: Hayden Laccabue Signed-off-by: David Zhang Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Lizhi Hou Link: https://patch.msgid.link/20260505160936.3917732-5-lizhi.hou@amd.com --- drivers/accel/amdxdna/aie4_ctx.c | 75 +++++++++++++++++++++++++++++++++ drivers/accel/amdxdna/aie4_host_queue.h | 2 + drivers/accel/amdxdna/aie4_pci.c | 34 +++++++++++++++ drivers/accel/amdxdna/aie4_pci.h | 3 ++ drivers/accel/amdxdna/amdxdna_ctx.c | 34 +++++++++++++++ drivers/accel/amdxdna/amdxdna_ctx.h | 4 +- drivers/accel/amdxdna/amdxdna_gem.c | 5 ++- drivers/accel/amdxdna/amdxdna_pci_drv.c | 18 +++++++- drivers/accel/amdxdna/amdxdna_pci_drv.h | 3 ++ drivers/accel/amdxdna/npu3_regs.c | 5 +++ include/uapi/drm/amdxdna_accel.h | 22 +++++++++- 11 files changed, 198 insertions(+), 7 deletions(-) (limited to 'include/uapi') diff --git a/drivers/accel/amdxdna/aie4_ctx.c b/drivers/accel/amdxdna/aie4_ctx.c index 84ac706d0ffb..8408b0d2696f 100644 --- a/drivers/accel/amdxdna/aie4_ctx.c +++ b/drivers/accel/amdxdna/aie4_ctx.c @@ -256,3 +256,78 @@ void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx) aie4_hwctx_umq_fini(hwctx); kfree(hwctx->priv); } + +static inline bool valid_queue_index(u64 read, u64 write, u32 capacity) +{ + return (write >= read) && ((write - read) <= capacity); +} + +static u64 get_read_index(struct amdxdna_hwctx *hwctx) +{ + u64 wi = READ_ONCE(*hwctx->priv->umq_write_index); + u64 ri = READ_ONCE(*hwctx->priv->umq_read_index); + struct amdxdna_dev *xdna = hwctx->client->xdna; + + /* + * CERT cannot update read index as uint64 atomically. Driver may read + * half-updated read index when it has bits in high 32bit. In case read + * index is not valid, wait for some time and retry once. It should + * allow CERT to complete the read index update. + */ + if (!valid_queue_index(ri, wi, CTX_MAX_CMDS)) { + XDNA_WARN(xdna, "Invalid index, ri %llu, wi %llu", ri, wi); + usleep_range(100, 200); + ri = READ_ONCE(*hwctx->priv->umq_read_index); + if (!valid_queue_index(ri, wi, CTX_MAX_CMDS)) { + XDNA_ERR(xdna, "Invalid index after retry, ri %llu, wi %llu", ri, wi); + ri = 0; + } + } + + return ri; +} + +static inline bool check_cmd_done(struct amdxdna_hwctx *hwctx, u64 seq) +{ + u64 read_idx = get_read_index(hwctx); + + return read_idx > seq; +} + +int aie4_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout) +{ + unsigned long wait_jifs = MAX_SCHEDULE_TIMEOUT; + struct amdxdna_hwctx_priv *priv = hwctx->priv; + struct cert_comp *cert_comp = priv->cert_comp; + long ret; + + if (timeout) + wait_jifs = msecs_to_jiffies(timeout); + + ret = wait_event_interruptible_timeout(cert_comp->waitq, + (check_cmd_done(hwctx, seq)), + wait_jifs); + + if (!ret) + ret = -ETIME; + + return ret <= 0 ? ret : 0; +} + +int aie4_hwctx_valid_doorbell(struct amdxdna_client *client, u32 vm_pgoff) +{ + struct amdxdna_hwctx *hwctx; + unsigned long hwctx_id; + int idx; + + idx = srcu_read_lock(&client->hwctx_srcu); + amdxdna_for_each_hwctx(client, hwctx_id, hwctx) { + if (vm_pgoff == (hwctx->doorbell_offset >> PAGE_SHIFT)) { + srcu_read_unlock(&client->hwctx_srcu, idx); + return 1; + } + } + srcu_read_unlock(&client->hwctx_srcu, idx); + + return 0; +} diff --git a/drivers/accel/amdxdna/aie4_host_queue.h b/drivers/accel/amdxdna/aie4_host_queue.h index eb6a38dfb53e..1b33eda3f727 100644 --- a/drivers/accel/amdxdna/aie4_host_queue.h +++ b/drivers/accel/amdxdna/aie4_host_queue.h @@ -8,6 +8,8 @@ #include +#define CTX_MAX_CMDS 32 + struct host_queue_header { __u64 read_index; struct { diff --git a/drivers/accel/amdxdna/aie4_pci.c b/drivers/accel/amdxdna/aie4_pci.c index 3be9066b7178..9ff34ce57fcb 100644 --- a/drivers/accel/amdxdna/aie4_pci.c +++ b/drivers/accel/amdxdna/aie4_pci.c @@ -503,6 +503,38 @@ static int aie4m_pcidev_init(struct amdxdna_dev *xdna) return 0; } +static int aie4_doorbell_mmap(struct amdxdna_client *client, struct vm_area_struct *vma) +{ + struct amdxdna_dev *xdna = client->xdna; + struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev); + const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv; + phys_addr_t res_start; + unsigned long pfn; + int ret; + + if (!aie4_hwctx_valid_doorbell(client, vma->vm_pgoff)) { + XDNA_ERR(xdna, "Invalid doorbell page offset 0x%lx", vma->vm_pgoff); + return -EINVAL; + } + + if (vma_pages(vma) != 1) { + XDNA_ERR(xdna, "can only map one page, got %ld", vma_pages(vma)); + return -EINVAL; + } + + res_start = pci_resource_start(pdev, xdna->dev_info->doorbell_bar) + npriv->doorbell_off; + pfn = PHYS_PFN(res_start) + vma->vm_pgoff; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP); + ret = io_remap_pfn_range(vma, vma->vm_start, + pfn, + PAGE_SIZE, + vma->vm_page_prot); + + XDNA_DBG(xdna, "doorbell ret %d", ret); + return ret; +} + static int aie4_pf_init(struct amdxdna_dev *xdna) { int ret; @@ -547,4 +579,6 @@ const struct amdxdna_dev_ops aie4_vf_ops = { .fini = aie4_vf_fini, .hwctx_init = aie4_hwctx_init, .hwctx_fini = aie4_hwctx_fini, + .mmap = aie4_doorbell_mmap, + .cmd_wait = aie4_cmd_wait, }; diff --git a/drivers/accel/amdxdna/aie4_pci.h b/drivers/accel/amdxdna/aie4_pci.h index 6103007e6d2f..b69489acd53d 100644 --- a/drivers/accel/amdxdna/aie4_pci.h +++ b/drivers/accel/amdxdna/aie4_pci.h @@ -36,6 +36,7 @@ struct amdxdna_dev_priv { u32 mbox_bar; u32 mbox_rbuf_bar; u64 mbox_info_off; + u32 doorbell_off; struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS]; struct aie_bar_off_pair smu_regs_off[SMU_MAX_REGS]; @@ -60,6 +61,8 @@ int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev); /* aie4_ctx.c */ int aie4_hwctx_init(struct amdxdna_hwctx *hwctx); void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx); +int aie4_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout); +int aie4_hwctx_valid_doorbell(struct amdxdna_client *client, u32 vm_pgoff); /* aie4_sriov.c */ #if IS_ENABLED(CONFIG_PCI_IOV) diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c index b5ad60d4b734..b79229a63af3 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.c +++ b/drivers/accel/amdxdna/amdxdna_ctx.c @@ -627,3 +627,37 @@ int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_ XDNA_ERR(client->xdna, "Invalid command type %d", args->type); return -EINVAL; } + +int amdxdna_drm_wait_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +{ + struct amdxdna_client *client = filp->driver_priv; + struct amdxdna_dev *xdna = to_xdna_dev(dev); + struct amdxdna_drm_wait_cmd *args = data; + struct amdxdna_hwctx *hwctx; + int ret, idx; + + XDNA_DBG(xdna, "PID %d ctx %d timeout set %d ms for cmd %llu", + client->pid, args->hwctx, args->timeout, args->seq); + + if (!xdna->dev_info->ops->cmd_wait) + return -EOPNOTSUPP; + + idx = srcu_read_lock(&client->hwctx_srcu); + hwctx = xa_load(&client->hwctx_xa, args->hwctx); + if (!hwctx) { + XDNA_DBG(xdna, "PID %d failed to get ctx %d", client->pid, args->hwctx); + ret = -EINVAL; + goto unlock_ctx_srcu; + } + + ret = xdna->dev_info->ops->cmd_wait(hwctx, args->seq, args->timeout); + + XDNA_DBG(xdna, "PID %d ctx %d cmd %lld wait finished, ret %d", + client->pid, args->hwctx, args->seq, ret); + + trace_amdxdna_debug_point(current->comm, args->seq, "job returned to user"); + +unlock_ctx_srcu: + srcu_read_unlock(&client->hwctx_srcu, idx); + return ret; +} diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index c5622718b4d5..6e3c6371a088 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -211,12 +211,10 @@ int amdxdna_cmd_submit(struct amdxdna_client *client, u32 *arg_bo_hdls, u32 arg_bo_cnt, u32 hwctx_hdl, u64 *seq); -int amdxdna_cmd_wait(struct amdxdna_client *client, u32 hwctx_hdl, - u64 seq, u32 timeout); - int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int amdxdna_drm_wait_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); #endif /* _AMDXDNA_CTX_H_ */ diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c index ebfc472aa9e7..319d2064fafa 100644 --- a/drivers/accel/amdxdna/amdxdna_gem.c +++ b/drivers/accel/amdxdna/amdxdna_gem.c @@ -212,7 +212,8 @@ static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni, mmu_interval_set_seq(&mapp->notifier, cur_seq); up_write(&xdna->notifier_lock); - xdna->dev_info->ops->hmm_invalidate(abo, cur_seq); + if (xdna->dev_info->ops->hmm_invalidate) + xdna->dev_info->ops->hmm_invalidate(abo, cur_seq); if (range->event == MMU_NOTIFY_UNMAP) { down_write(&xdna->notifier_lock); @@ -295,7 +296,7 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo, u32 nr_pages; int ret; - if (!xdna->dev_info->ops->hmm_invalidate) + if (!amdxdna_pasid_on(abo->client)) return 0; mapp = kzalloc_obj(*mapp); diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 39ad081ac082..c0d00db25cde 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -224,6 +224,21 @@ static int amdxdna_drm_set_state_ioctl(struct drm_device *dev, void *data, struc return ret; } +static int amdxdna_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *drm_filp = filp->private_data; + struct amdxdna_client *client = drm_filp->driver_priv; + struct amdxdna_dev *xdna = client->xdna; + + if (likely(vma->vm_pgoff >= DRM_FILE_PAGE_OFFSET_START)) + return drm_gem_mmap(filp, vma); + + if (!xdna->dev_info->ops->mmap) + return -EOPNOTSUPP; + + return xdna->dev_info->ops->mmap(client, vma); +} + static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = { /* Context */ DRM_IOCTL_DEF_DRV(AMDXDNA_CREATE_HWCTX, amdxdna_drm_create_hwctx_ioctl, 0), @@ -235,6 +250,7 @@ static const struct drm_ioctl_desc amdxdna_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(AMDXDNA_SYNC_BO, amdxdna_drm_sync_bo_ioctl, 0), /* Execution */ DRM_IOCTL_DEF_DRV(AMDXDNA_EXEC_CMD, amdxdna_drm_submit_cmd_ioctl, 0), + DRM_IOCTL_DEF_DRV(AMDXDNA_WAIT_CMD, amdxdna_drm_wait_cmd_ioctl, 0), /* AIE hardware */ DRM_IOCTL_DEF_DRV(AMDXDNA_GET_INFO, amdxdna_drm_get_info_ioctl, 0), DRM_IOCTL_DEF_DRV(AMDXDNA_GET_ARRAY, amdxdna_drm_get_array_ioctl, 0), @@ -281,7 +297,7 @@ static const struct file_operations amdxdna_fops = { .poll = drm_poll, .read = drm_read, .llseek = noop_llseek, - .mmap = drm_gem_mmap, + .mmap = amdxdna_drm_gem_mmap, .show_fdinfo = drm_show_fdinfo, .fop_flags = FOP_UNSIGNED_OFFSET, }; diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index caed11c09e55..471b72299aee 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -56,12 +56,14 @@ struct amdxdna_dev_ops { int (*resume)(struct amdxdna_dev *xdna); int (*suspend)(struct amdxdna_dev *xdna); int (*sriov_configure)(struct amdxdna_dev *xdna, int num_vfs); + int (*mmap)(struct amdxdna_client *client, struct vm_area_struct *vma); int (*hwctx_init)(struct amdxdna_hwctx *hwctx); void (*hwctx_fini)(struct amdxdna_hwctx *hwctx); int (*hwctx_config)(struct amdxdna_hwctx *hwctx, u32 type, u64 value, void *buf, u32 size); int (*hwctx_sync_debug_bo)(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl); void (*hmm_invalidate)(struct amdxdna_gem_obj *abo, unsigned long cur_seq); int (*cmd_submit)(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq); + int (*cmd_wait)(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout); int (*get_aie_info)(struct amdxdna_client *client, struct amdxdna_drm_get_info *args); int (*set_aie_state)(struct amdxdna_client *client, struct amdxdna_drm_set_state *args); int (*get_array)(struct amdxdna_client *client, struct amdxdna_drm_get_array *args); @@ -85,6 +87,7 @@ struct amdxdna_dev_info { int sram_bar; int psp_bar; int smu_bar; + int doorbell_bar; int device_type; int first_col; u32 dev_mem_buf_shift; diff --git a/drivers/accel/amdxdna/npu3_regs.c b/drivers/accel/amdxdna/npu3_regs.c index 6d5da779232b..d76b2e99c308 100644 --- a/drivers/accel/amdxdna/npu3_regs.c +++ b/drivers/accel/amdxdna/npu3_regs.c @@ -14,6 +14,9 @@ #define NPU3_MBOX_BUFFER_BAR 2 #define NPU3_MBOX_INFO_OFF 0x0 +#define NPU3_DOORBELL_BAR 2 +#define NPU3_DOORBELL_OFF 0x0 + /* PCIe BAR Index for NPU3 */ #define NPU3_REG_BAR_INDEX 0 #define NPU3_PSP_BAR_INDEX 4 @@ -45,6 +48,7 @@ static const struct amdxdna_dev_priv npu3_dev_priv = { .mbox_bar = NPU3_MBOX_BAR, .mbox_rbuf_bar = NPU3_MBOX_BUFFER_BAR, .mbox_info_off = NPU3_MBOX_INFO_OFF, + .doorbell_off = NPU3_DOORBELL_OFF, .psp_regs_off = { DEFINE_BAR_OFFSET(PSP_CMD_REG, NPU3_PSP, MPASP_C2PMSG_123_ALT_1), DEFINE_BAR_OFFSET(PSP_ARG0_REG, NPU3_PSP, MPASP_C2PMSG_156_ALT_1), @@ -87,6 +91,7 @@ const struct amdxdna_dev_info dev_npu3_pf_info = { const struct amdxdna_dev_info dev_npu3_vf_info = { .mbox_bar = NPU3_MBOX_BAR, .sram_bar = NPU3_MBOX_BUFFER_BAR, + .doorbell_bar = NPU3_DOORBELL_BAR, .default_vbnv = "RyzenAI-npu3-vf", .device_type = AMDXDNA_DEV_TYPE_UMQ, .dev_priv = &npu3_dev_vf_priv, diff --git a/include/uapi/drm/amdxdna_accel.h b/include/uapi/drm/amdxdna_accel.h index ad9b33dd7b13..51a507561df6 100644 --- a/include/uapi/drm/amdxdna_accel.h +++ b/include/uapi/drm/amdxdna_accel.h @@ -45,7 +45,8 @@ enum amdxdna_drm_ioctl_id { DRM_AMDXDNA_EXEC_CMD, DRM_AMDXDNA_GET_INFO, DRM_AMDXDNA_SET_STATE, - DRM_AMDXDNA_GET_ARRAY = 10, + DRM_AMDXDNA_WAIT_CMD, + DRM_AMDXDNA_GET_ARRAY, }; /** @@ -274,6 +275,21 @@ struct amdxdna_drm_exec_cmd { __u64 seq; }; +/** + * struct amdxdna_drm_wait_cmd - Wait execution command. + * + * @hwctx: Context handle. + * @timeout: timeout in ms, 0 implies infinite wait. + * @seq: sequence number of the command returned by execute command. + * + * Wait a command specified by seq to be completed. + */ +struct amdxdna_drm_wait_cmd { + __u32 hwctx; + __u32 timeout; + __u64 seq; +}; + /** * struct amdxdna_drm_query_aie_status - Query the status of the AIE hardware * @buffer: The user space buffer that will return the AIE status. @@ -739,6 +755,10 @@ struct amdxdna_drm_set_power_mode { DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDXDNA_GET_ARRAY, \ struct amdxdna_drm_get_array) +#define DRM_IOCTL_AMDXDNA_WAIT_CMD \ + DRM_IOW(DRM_COMMAND_BASE + DRM_AMDXDNA_WAIT_CMD, \ + struct amdxdna_drm_wait_cmd) + #if defined(__cplusplus) } /* extern c end */ #endif -- cgit v1.2.3 From 19d584a634fe999786acfb0ac5289710cc84a5f6 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Mon, 4 May 2026 11:53:27 +1200 Subject: drm/fourcc: Fix descriptions of 32b float formats The channels were described in reverse format, i.e. RGBA instead of ABGR Signed-off-by: Robert Ancell CC: Rob Clark Reviewed-by: Simon Ser Signed-off-by: Simon Ser Link: https://patch.msgid.link/20260503235327.92428-1-robert.ancell@canonical.com --- include/uapi/drm/drm_fourcc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 15aa0a8f44b0..3a4d4dc635bf 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -224,9 +224,9 @@ extern "C" { * [31:0] sign:exponent:mantissa 1:8:23 */ #define DRM_FORMAT_R32F fourcc_code('R', ' ', ' ', 'F') /* [31:0] R 32 little endian */ -#define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] R:G 32:32 little endian */ -#define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] R:G:B 32:32:32 little endian */ -#define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] R:G:B:A 32:32:32:32 little endian */ +#define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] G:R 32:32 little endian */ +#define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] B:G:R 32:32:32 little endian */ +#define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] A:B:G:R 32:32:32:32 little endian */ /* * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits -- cgit v1.2.3 From a789761de3053d25f03787ac40897dbea14ee368 Mon Sep 17 00:00:00 2001 From: Benjamin Welton Date: Mon, 9 Feb 2026 00:42:00 +0800 Subject: amd/amdkfd: Add kfd_ioctl_profiler to contain profiler kernel driver changes kfd_ioctl_profiler takes a similar approach to that of kfd_ioctl_dbg_trap (which contains debugger related IOCTL services) where kfd_ioctl_profiler will contain all profiler related IOCTL services. The IOCTL is designed to be expanded as needed to support additional profiler functionality. The current functionality of the IOCTL is to allow for profilers which need PMC counters from GPU devices to both signal to other profilers that may be on the system that the device has active PMC profiling taking place on it (multiple PMC profilers on the same device can result in corrupted counter data) and to setup the device to allow for the collection of SQ PMC data on all queues on the device. For PMC data for the SQ block (such as SQ_WAVES) to be available to a profiler, mmPERFCOUNT_ENABLE must be set on the queues. When profiling a single process, the profiler can inject PM4 packets into each queue to turn on PERFCOUNT_ENABLE. When profiling system wide, the profiler does not have this option and must have a way to turn on profiling for queues in which it cannot inject packets into directly. Accomplishing this requires a few steps: 1. Checking if the user has the necessary permissions to profile system wide on the device. This check uses the same check that linux perf uses to determine if a user has the necessary permissions to profile at this scope (primarily if the process has CAP_SYS_PERFMON or is root). 2. Locking the device for profiling. This is done by setting a lock bit on the device struct and storing the process that locked the device. 3. Iterating all queues on the device and issuing an MQD Update to enable perfcounting on the queues. 4. Actions to cleanup if the process exits or releases the lock. The IOCTL also contains a link to the existing PC Sampling IOCTL as well. This is per a suggestion that we should potentially remove the PC Sampling IOCTL to have it be a part of the profiler IOCTL. This is a future change. In addition, we do expect to expand the profiler IOCTL to include additional profiler functionality in the future (which necessitates the use of a version number). v2: sqaush in proper IOCTL number Proposed userpace support: https://github.com/ROCm/rocm-systems/commit/40abc95a6463a61bb318a67efd6d9cc3e5ee8839 Signed-off-by: Benjamin Welton Signed-off-by: Perry Yuan Acked-by: Kent Russell Reviewed-by: Yifan Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 82 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 4 ++ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 25 +++++++ .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.h | 2 + drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c | 16 ++++- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c | 14 +++- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c | 8 ++- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 15 +++- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 11 +++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 7 ++ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 11 +++ include/uapi/linux/kfd_ioctl.h | 28 +++++++- 12 files changed, 214 insertions(+), 9 deletions(-) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index dd27d7ba2ee2..d18ec3671fda 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -21,6 +21,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -3216,6 +3217,84 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v return 0; } +static inline uint32_t profile_lock_device(struct kfd_process *p, + uint32_t gpu_id, uint32_t op) +{ + struct kfd_process_device *pdd; + struct kfd_dev *kfd; + int status = -EINVAL; + + if (!p) + return -EINVAL; + + mutex_lock(&p->mutex); + pdd = kfd_process_device_data_by_id(p, gpu_id); + mutex_unlock(&p->mutex); + + if (!pdd || !pdd->dev || !pdd->dev->kfd) + return -EINVAL; + + kfd = pdd->dev->kfd; + + mutex_lock(&kfd->profiler_lock); + if (op == 1) { + if (!kfd->profiler_process) { + kfd->profiler_process = p; + status = 0; + } else if (kfd->profiler_process == p) { + status = -EALREADY; + } else { + status = -EBUSY; + } + } else if (op == 0 && kfd->profiler_process == p) { + kfd->profiler_process = NULL; + status = 0; + } + mutex_unlock(&kfd->profiler_lock); + + return status; +} + +static inline int kfd_profiler_pmc(struct kfd_process *p, + struct kfd_ioctl_pmc_settings *args) +{ + struct kfd_process_device *pdd; + struct device_queue_manager *dqm; + int status; + + /* Check if we have the correct permissions. */ + if (!perfmon_capable()) + return -EPERM; + + /* Lock/Unlock the device based on the parameter given in OP */ + status = profile_lock_device(p, args->gpu_id, args->lock); + if (status != 0) + return status; + + /* Enable/disable perfcount if requested */ + mutex_lock(&p->mutex); + pdd = kfd_process_device_data_by_id(p, args->gpu_id); + dqm = pdd->dev->dqm; + mutex_unlock(&p->mutex); + + dqm->ops.set_perfcount(dqm, args->perfcount_enable); + return status; +} + +static int kfd_ioctl_profiler(struct file *filep, struct kfd_process *p, void *data) +{ + struct kfd_ioctl_profiler_args *args = data; + + switch (args->op) { + case KFD_IOC_PROFILER_VERSION: + args->version = KFD_IOC_PROFILER_VERSION_NUM; + return 0; + case KFD_IOC_PROFILER_PMC: + return kfd_profiler_pmc(p, &args->pmc); + } + return -EINVAL; +} + #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \ [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, \ .validate = NULL, .cmd_drv = 0, .name = #ioctl} @@ -3342,6 +3421,9 @@ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = { AMDKFD_IOCTL_DEF(AMDKFD_IOC_CREATE_PROCESS, kfd_ioctl_create_process, 0), + + AMDKFD_IOCTL_DEF(AMDKFD_IOC_PROFILER, + kfd_ioctl_profiler, 0), }; #define AMDKFD_CORE_IOCTL_COUNT ARRAY_SIZE(amdkfd_ioctls) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index b7f8f7ff8198..d649d8603e28 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -936,6 +936,9 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd, svm_range_set_max_pages(kfd->adev); + kfd->profiler_process = NULL; + mutex_init(&kfd->profiler_lock); + kfd->init_complete = true; dev_info(kfd_device, "added device %x:%x\n", kfd->adev->pdev->vendor, kfd->adev->pdev->device); @@ -971,6 +974,7 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd) ida_destroy(&kfd->doorbell_ida); kfd_gtt_sa_fini(kfd); amdgpu_amdkfd_free_kernel_mem(kfd->adev, &kfd->gtt_mem); + mutex_destroy(&kfd->profiler_lock); } kfree(kfd); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index a9ac575537e5..c64a1e19fa3f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -324,6 +324,29 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st return r; } +static void set_perfcount(struct device_queue_manager *dqm, int enable) +{ + struct device_process_node *cur; + struct qcm_process_device *qpd; + struct queue *q; + struct mqd_update_info minfo = { 0 }; + + if (!dqm) + return; + + minfo.update_flag = (enable == 1 ? UPDATE_FLAG_PERFCOUNT_ENABLE : + UPDATE_FLAG_PERFCOUNT_DISABLE); + dqm_lock(dqm); + list_for_each_entry(cur, &dqm->queues, list) { + qpd = cur->qpd; + list_for_each_entry(q, &qpd->queues_list, list) { + pqm_update_mqd(qpd->pqm, q->properties.queue_id, + &minfo); + } + } + dqm_unlock(dqm); +} + static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { @@ -3113,6 +3136,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) dqm->ops.reset_queues = reset_queues_cpsch; dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info; dqm->ops.checkpoint_mqd = checkpoint_mqd; + dqm->ops.set_perfcount = set_perfcount; break; case KFD_SCHED_POLICY_NO_HWS: /* initialize dqm for no cp scheduling */ @@ -3133,6 +3157,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) dqm->ops.get_wave_state = get_wave_state; dqm->ops.get_queue_checkpoint_info = get_queue_checkpoint_info; dqm->ops.checkpoint_mqd = checkpoint_mqd; + dqm->ops.set_perfcount = set_perfcount; break; default: dev_err(dev->adev->dev, "Invalid scheduling policy %d\n", dqm->sched_policy); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index a0323501c6b9..e0b6a47e7722 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -199,6 +199,8 @@ struct device_queue_manager_ops { const struct queue *q, void *mqd, void *ctl_stack); + void (*set_perfcount)(struct device_queue_manager *dqm, + int enable); }; struct device_queue_manager_asic_ops { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 77fb41e2486a..8e8ec266ca46 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -123,10 +123,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, */ m->cp_hqd_hq_scheduler0 = 1 << 14; - if (q->format == KFD_QUEUE_FORMAT_AQL) { + if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - } if (mm->dev->kfd->cwsr_enabled) { m->cp_hqd_persistent_state |= @@ -141,6 +140,12 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -220,6 +225,13 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->kfd->cwsr_enabled) m->cp_hqd_ctx_save_control = 0; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } + update_cu_mask(mm, mqd, minfo); set_priority(m, q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index a1e3cf2384dd..7568e7ed5244 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -163,10 +163,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, if (amdgpu_amdkfd_have_atomics_support(mm->dev->adev)) m->cp_hqd_hq_status0 |= 1 << 29; - if (q->format == KFD_QUEUE_FORMAT_AQL) { + if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - } if (mm->dev->kfd->cwsr_enabled) { m->cp_hqd_persistent_state |= @@ -181,6 +180,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -258,6 +262,12 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, } if (mm->dev->kfd->cwsr_enabled) m->cp_hqd_ctx_save_control = 0; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } update_cu_mask(mm, mqd, minfo); set_priority(m, q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c index b3e122d7876e..8c815f129614 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c @@ -138,10 +138,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, if (amdgpu_amdkfd_have_atomics_support(mm->dev->adev)) m->cp_hqd_hq_status0 |= 1 << 29; - if (q->format == KFD_QUEUE_FORMAT_AQL) { + if (q->format == KFD_QUEUE_FORMAT_AQL) m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - } if (mm->dev->kfd->cwsr_enabled) { m->cp_hqd_persistent_state |= @@ -156,6 +155,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index e8f97de9d6e4..56a7679ca98d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -227,10 +227,9 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_aql_control = 1 << CP_HQD_AQL_CONTROL__CONTROL0__SHIFT; - if (q->tba_addr) { + if (q->tba_addr) m->compute_pgm_rsrc2 |= (1 << COMPUTE_PGM_RSRC2__TRAP_PRESENT__SHIFT); - } if (mm->dev->kfd->cwsr_enabled && q->ctx_save_restore_area_address) { m->cp_hqd_persistent_state |= @@ -245,6 +244,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -327,6 +331,13 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->kfd->cwsr_enabled && q->ctx_save_restore_area_address) m->cp_hqd_ctx_save_control = 0; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } + if (KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 4, 3) && KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 4, 4) && KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 5, 0)) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 431a20323146..c86779af323b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -148,6 +148,11 @@ static void init_mqd(struct mqd_manager *mm, void **mqd, m->cp_hqd_wg_state_offset = q->ctl_stack_size; } + mutex_lock(&mm->dev->kfd->profiler_lock); + if (mm->dev->kfd->profiler_process != NULL) + m->compute_perfcount_enable = 1; + mutex_unlock(&mm->dev->kfd->profiler_lock); + *mqd = m; if (gart_addr) *gart_addr = addr; @@ -230,6 +235,12 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_ctx_save_control = atc_bit << CP_HQD_CTX_SAVE_CONTROL__ATC__SHIFT | mtype << CP_HQD_CTX_SAVE_CONTROL__MTYPE__SHIFT; + if (minfo) { + if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_ENABLE) + m->compute_perfcount_enable = 1; + else if (minfo->update_flag == UPDATE_FLAG_PERFCOUNT_DISABLE) + m->compute_perfcount_enable = 0; + } update_cu_mask(mm, mqd, minfo); set_priority(m, q); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 9fe5c66d8013..903386e0740b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -383,6 +383,11 @@ struct kfd_dev { int kfd_dev_lock; atomic_t kfd_processes_count; + + /* Lock for profiler process */ + struct mutex profiler_lock; + /* Process currently holding the lock */ + struct kfd_process *profiler_process; }; enum kfd_mempool { @@ -556,6 +561,8 @@ enum mqd_update_flag { UPDATE_FLAG_DBG_WA_ENABLE = 1, UPDATE_FLAG_DBG_WA_DISABLE = 2, UPDATE_FLAG_IS_GWS = 4, /* quirk for gfx9 IP */ + UPDATE_FLAG_PERFCOUNT_ENABLE = 5, + UPDATE_FLAG_PERFCOUNT_DISABLE = 6, }; struct mqd_update_info { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 9228e4a949ed..1a8cb512dfe3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1106,6 +1106,16 @@ static void kfd_process_free_outstanding_kfd_bos(struct kfd_process *p) kfd_process_device_free_bos(p->pdds[i]); } +static void kfd_process_profiler_release(struct kfd_process *p, struct kfd_process_device *pdd) +{ + mutex_lock(&pdd->dev->kfd->profiler_lock); + if (pdd->dev->kfd->profiler_process == p) { + pdd->qpd.dqm->ops.set_perfcount(pdd->qpd.dqm, 0); + pdd->dev->kfd->profiler_process = NULL; + } + mutex_unlock(&pdd->dev->kfd->profiler_lock); +} + static void kfd_process_destroy_pdds(struct kfd_process *p) { int i; @@ -1117,6 +1127,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) pr_debug("Releasing pdd (topology id %d, for pid %d)\n", pdd->dev->id, p->lead_thread->pid); + kfd_process_profiler_release(p, pdd); kfd_process_device_destroy_cwsr_dgpu(pdd); kfd_process_device_destroy_ib_mem(pdd); diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index e72359370857..cc3ed0765c83 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -1558,6 +1558,29 @@ struct kfd_ioctl_dbg_trap_args { }; }; +#define KFD_IOC_PROFILER_VERSION_NUM 1 +enum kfd_profiler_ops { + KFD_IOC_PROFILER_PMC = 0, + KFD_IOC_PROFILER_VERSION = 2, +}; + +/** + * Enables/Disables GPU Specific profiler settings + */ +struct kfd_ioctl_pmc_settings { + __u32 gpu_id; /* This is the user_gpu_id */ + __u32 lock; /* Lock GPU for Profiling */ + __u32 perfcount_enable; /* Force Perfcount Enable for queues on GPU */ +}; + +struct kfd_ioctl_profiler_args { + __u32 op; /* kfd_profiler_op */ + union { + struct kfd_ioctl_pmc_settings pmc; + __u32 version; /* KFD_IOC_PROFILER_VERSION_NUM */ + }; +}; + #define AMDKFD_IOCTL_BASE 'K' #define AMDKFD_IO(nr) _IO(AMDKFD_IOCTL_BASE, nr) #define AMDKFD_IOR(nr, type) _IOR(AMDKFD_IOCTL_BASE, nr, type) @@ -1681,7 +1704,10 @@ struct kfd_ioctl_dbg_trap_args { #define AMDKFD_IOC_CREATE_PROCESS \ AMDKFD_IO(0x27) +#define AMDKFD_IOC_PROFILER \ + AMDKFD_IOWR(0x28, struct kfd_ioctl_profiler_args) + #define AMDKFD_COMMAND_START 0x01 -#define AMDKFD_COMMAND_END 0x28 +#define AMDKFD_COMMAND_END 0x29 #endif -- cgit v1.2.3 From dd61e27535a6f5cfb32a847b282d2e3d5aebf46f Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Mon, 9 Feb 2026 00:42:07 +0800 Subject: drm/amdkfd: Add PTL control IOCTL Option and unify refcount logic Introduce a new IOCTL option to allow userspace explicit control over the Peak Tops Limiter (PTL) state for profiling Link: https://github.com/ROCm/rocm-systems/tree/develop/projects/rocprofiler-sdk Signed-off-by: Perry Yuan Reviewed-by: Yifan Zhang Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 2 + drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 102 +++++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 8 +++ drivers/gpu/drm/amd/amdkfd/kfd_process.c | 4 ++ drivers/gpu/drm/amd/include/amdgpu_ptl.h | 2 + include/uapi/linux/kfd_ioctl.h | 7 +++ 6 files changed, 125 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 467a3dbe1bfa..aab6a4de54fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -2400,6 +2400,8 @@ static int gfx_v9_4_3_perf_monitor_ptl_init(struct amdgpu_device *adev, bool ena ptl->hw_supported = true; + atomic_set(&ptl->disable_ref, 0); + return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index fc00d0418684..883de31df04d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1774,6 +1774,104 @@ static int kfd_ioctl_svm(struct file *filep, struct kfd_process *p, void *data) } #endif +static int kfd_ptl_control(struct kfd_process_device *pdd, bool enable) +{ + struct amdgpu_device *adev = pdd->dev->adev; + struct amdgpu_ptl *ptl = &adev->psp.ptl; + enum amdgpu_ptl_fmt pref_format1 = ptl->fmt1; + enum amdgpu_ptl_fmt pref_format2 = ptl->fmt2; + uint32_t ptl_state = enable ? 1 : 0; + int ret; + + if (!ptl->hw_supported) + return -EOPNOTSUPP; + + if (!pdd->dev->kfd2kgd || !pdd->dev->kfd2kgd->ptl_ctrl) + return -EOPNOTSUPP; + + ret = pdd->dev->kfd2kgd->ptl_ctrl(adev, PSP_PTL_PERF_MON_SET, + &ptl_state, + &pref_format1, + &pref_format2); + return ret; +} + +int kfd_ptl_disable_request(struct kfd_process_device *pdd, + struct kfd_process *p) +{ + struct amdgpu_device *adev = pdd->dev->adev; + struct amdgpu_ptl *ptl = &adev->psp.ptl; + int ret = 0; + + mutex_lock(&ptl->mutex); + + if (pdd->ptl_disable_req) + goto out; + + if (atomic_inc_return(&ptl->disable_ref) == 1) { + ret = kfd_ptl_control(pdd, false); + if (ret) { + atomic_dec(&ptl->disable_ref); + dev_warn(pdd->dev->adev->dev, + "failed to disable PTL\n"); + goto out; + } + } + pdd->ptl_disable_req = true; + +out: + mutex_unlock(&ptl->mutex); + return ret; +} + +int kfd_ptl_disable_release(struct kfd_process_device *pdd, + struct kfd_process *p) +{ + struct amdgpu_device *adev = pdd->dev->adev; + struct amdgpu_ptl *ptl = &adev->psp.ptl; + int ret = 0; + + mutex_lock(&ptl->mutex); + + if (!pdd->ptl_disable_req) + goto out; + + if (atomic_dec_return(&ptl->disable_ref) == 0) { + ret = kfd_ptl_control(pdd, true); + if (ret) { + atomic_inc(&ptl->disable_ref); + dev_warn(adev->dev, "Failed to enable PTL on release: %d\n", ret); + goto out; + } + } + pdd->ptl_disable_req = false; + +out: + mutex_unlock(&ptl->mutex); + return ret; +} + +static int kfd_profiler_ptl_control(struct kfd_process *p, + struct kfd_ioctl_ptl_control *args) +{ + struct kfd_process_device *pdd; + int ret; + + mutex_lock(&p->mutex); + pdd = kfd_process_device_data_by_id(p, args->gpu_id); + mutex_unlock(&p->mutex); + + if (!pdd || !pdd->dev || !pdd->dev->kfd) + return -EINVAL; + + if (args->enable == 0) + ret = kfd_ptl_disable_request(pdd, p); + else + ret = kfd_ptl_disable_release(pdd, p); + + return ret; +} + static int criu_checkpoint_process(struct kfd_process *p, uint8_t __user *user_priv_data, uint64_t *priv_offset) @@ -3242,6 +3340,7 @@ static inline uint32_t profile_lock_device(struct kfd_process *p, if (!kfd->profiler_process) { kfd->profiler_process = p; status = 0; + kfd_ptl_disable_request(pdd, p); } else if (kfd->profiler_process == p) { status = -EALREADY; } else { @@ -3250,6 +3349,7 @@ static inline uint32_t profile_lock_device(struct kfd_process *p, } else if (op == 0 && kfd->profiler_process == p) { kfd->profiler_process = NULL; status = 0; + kfd_ptl_disable_release(pdd, p); } mutex_unlock(&kfd->profiler_lock); @@ -3292,6 +3392,8 @@ static int kfd_ioctl_profiler(struct file *filep, struct kfd_process *p, void *d return 0; case KFD_IOC_PROFILER_PMC: return kfd_profiler_pmc(p, &args->pmc); + case KFD_IOC_PROFILER_PTL_CONTROL: + return kfd_profiler_ptl_control(p, &args->ptl); } return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 903386e0740b..482bcfa10f82 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -872,6 +872,8 @@ struct kfd_process_device { bool has_reset_queue; u32 pasid; + /* Indicates this process has requested PTL stay disabled */ + bool ptl_disable_req; }; #define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd) @@ -1603,6 +1605,12 @@ static inline bool kfd_is_first_node(struct kfd_node *node) return (node == node->kfd->nodes[0]); } +/* PTL support */ +int kfd_ptl_disable_request(struct kfd_process_device *pdd, + struct kfd_process *p); +int kfd_ptl_disable_release(struct kfd_process_device *pdd, + struct kfd_process *p); + /* Debugfs */ #if defined(CONFIG_DEBUG_FS) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 1a8cb512dfe3..368283d53077 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -1128,6 +1128,10 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) pr_debug("Releasing pdd (topology id %d, for pid %d)\n", pdd->dev->id, p->lead_thread->pid); kfd_process_profiler_release(p, pdd); + + if (pdd->ptl_disable_req) + kfd_ptl_disable_release(pdd, p); + kfd_process_device_destroy_cwsr_dgpu(pdd); kfd_process_device_destroy_ib_mem(pdd); diff --git a/drivers/gpu/drm/amd/include/amdgpu_ptl.h b/drivers/gpu/drm/amd/include/amdgpu_ptl.h index ffed443a14ae..9e63a9a9680a 100644 --- a/drivers/gpu/drm/amd/include/amdgpu_ptl.h +++ b/drivers/gpu/drm/amd/include/amdgpu_ptl.h @@ -39,6 +39,8 @@ struct amdgpu_ptl { enum amdgpu_ptl_fmt fmt2; bool enabled; bool hw_supported; + /* PTL disable reference counting */ + atomic_t disable_ref; struct mutex mutex; }; diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index cc3ed0765c83..1a94d512df35 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -1562,6 +1562,7 @@ struct kfd_ioctl_dbg_trap_args { enum kfd_profiler_ops { KFD_IOC_PROFILER_PMC = 0, KFD_IOC_PROFILER_VERSION = 2, + KFD_IOC_PROFILER_PTL_CONTROL = 3, }; /** @@ -1573,10 +1574,16 @@ struct kfd_ioctl_pmc_settings { __u32 perfcount_enable; /* Force Perfcount Enable for queues on GPU */ }; +struct kfd_ioctl_ptl_control { + __u32 gpu_id; /* user_gpu_id */ + __u32 enable; /* set 1 to enable PTL, set 0 to disable PTL */ +}; + struct kfd_ioctl_profiler_args { __u32 op; /* kfd_profiler_op */ union { struct kfd_ioctl_pmc_settings pmc; + struct kfd_ioctl_ptl_control ptl; __u32 version; /* KFD_IOC_PROFILER_VERSION_NUM */ }; }; -- cgit v1.2.3 From c62c076d2d64ead542c961cabed0f9467d7d6026 Mon Sep 17 00:00:00 2001 From: Perry Yuan Date: Wed, 15 Apr 2026 10:34:03 +0800 Subject: drm/amdkfd: bump KFD ioctl minor version to 1.23 Bump `KFD_IOCTL_MINOR_VERSION` from 22 to 23 and document version 1.23 in `kfd_ioctl.h` so userspace can detect profiler ioctl support. Signed-off-by: Perry Yuan Suggested-by: Alex Deucher Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- include/uapi/linux/kfd_ioctl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/uapi') diff --git a/include/uapi/linux/kfd_ioctl.h b/include/uapi/linux/kfd_ioctl.h index 1a94d512df35..9584b5aab727 100644 --- a/include/uapi/linux/kfd_ioctl.h +++ b/include/uapi/linux/kfd_ioctl.h @@ -48,9 +48,10 @@ * - 1.20 - Trap handler support for expert scheduling mode available * - 1.21 - Debugger support to subscribe to LDS out-of-address exceptions * - 1.22 - Add queue creation with metadata ring base address + * - 1.23 - Add profiler control ioctl to enable/disable profiler on a process */ #define KFD_IOCTL_MAJOR_VERSION 1 -#define KFD_IOCTL_MINOR_VERSION 22 +#define KFD_IOCTL_MINOR_VERSION 23 struct kfd_ioctl_get_version_args { __u32 major_version; /* from KFD */ -- cgit v1.2.3 From 4c26e162947f91aa78ba57dd4fddd38fc80e7d60 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 1 May 2026 03:00:43 +0300 Subject: drm/virtio: Extend blob UAPI with deferred-mapping hinting If userspace never maps GEM object, then BO wastes hostmem space because VirtIO-GPU driver maps VRAM BO at the BO's creating time. Make mappings on-demand by adding new RESOURCE_CREATE_BLOB IOCTL/UAPI hinting flag telling that host mapping should be deferred until first mapping is made when the flag is set by userspace. Signed-off-by: Dmitry Osipenko Reviewed-by: Rob Clark Link: https://patch.msgid.link/20260501000043.2483678-1-dmitry.osipenko@collabora.com --- drivers/gpu/drm/virtio/virtgpu_drv.h | 2 ++ drivers/gpu/drm/virtio/virtgpu_ioctl.c | 1 + drivers/gpu/drm/virtio/virtgpu_vram.c | 30 +++++++++++++++++++++++++----- include/uapi/drm/virtgpu_drm.h | 4 ++++ 4 files changed, 32 insertions(+), 5 deletions(-) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index f17660a71a3e..6f49213e23f8 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -84,6 +84,7 @@ struct virtio_gpu_object_params { uint32_t blob_mem; uint32_t blob_flags; uint64_t blob_id; + uint32_t blob_hints; }; struct virtio_gpu_object { @@ -507,6 +508,7 @@ struct sg_table *virtio_gpu_vram_map_dma_buf(struct virtio_gpu_object *bo, void virtio_gpu_vram_unmap_dma_buf(struct device *dev, struct sg_table *sgt, enum dma_data_direction dir); +void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram); /* virtgpu_submit.c */ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index c33c057365f8..01daa72b1310 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -489,6 +489,7 @@ static int verify_blob(struct virtio_gpu_device *vgdev, params->size = rc_blob->size; params->blob = true; params->blob_flags = rc_blob->blob_flags; + params->blob_hints = rc_blob->blob_hints; return 0; } diff --git a/drivers/gpu/drm/virtio/virtgpu_vram.c b/drivers/gpu/drm/virtio/virtgpu_vram.c index 084e80227433..4ae3cbc35dd3 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vram.c +++ b/drivers/gpu/drm/virtio/virtgpu_vram.c @@ -3,6 +3,8 @@ #include +static DEFINE_MUTEX(map_lock); + static void virtio_gpu_vram_free(struct drm_gem_object *obj) { struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); @@ -42,6 +44,11 @@ static int virtio_gpu_vram_mmap(struct drm_gem_object *obj, if (!(bo->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) return -EINVAL; + virtio_gpu_vram_map_deferred(vram); + + if (vram->map_state == STATE_INITIALIZING) + virtio_gpu_notify(vgdev); + wait_event(vgdev->resp_wq, vram->map_state != STATE_INITIALIZING); if (vram->map_state != STATE_OK) return -EINVAL; @@ -218,14 +225,27 @@ int virtio_gpu_vram_create(struct virtio_gpu_device *vgdev, virtio_gpu_cmd_resource_create_blob(vgdev, &vram->base, params, NULL, 0); - if (params->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) { - ret = virtio_gpu_vram_map(&vram->base); - if (ret) { - virtio_gpu_vram_free(obj); - return ret; + if (!(params->blob_hints & DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING)) { + if (params->blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE) { + ret = virtio_gpu_vram_map(&vram->base); + if (ret) { + virtio_gpu_vram_free(obj); + return ret; + } } } *bo_ptr = &vram->base; return 0; } + +void virtio_gpu_vram_map_deferred(struct virtio_gpu_object_vram *vram) +{ + if (!(vram->base.blob_flags & VIRTGPU_BLOB_FLAG_USE_MAPPABLE)) + return; + + mutex_lock(&map_lock); + if (!drm_mm_node_allocated(&vram->vram_node)) + virtio_gpu_vram_map(&vram->base); + mutex_unlock(&map_lock); +} diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index 9debb320c34b..ba09a4ee3e77 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -200,6 +200,10 @@ struct drm_virtgpu_resource_create_blob { __u32 cmd_size; __u64 cmd; __u64 blob_id; + +#define DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING 0x0001 + __u32 blob_hints; + __u32 pad2; }; #define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 -- cgit v1.2.3 From 7b5121c3374e24c8f6490b54f347eb06ee16028c Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Tue, 28 Apr 2026 21:44:48 +0200 Subject: drm/virtio: support VIRTIO_GPU_F_BLOB_ALIGNMENT Support VIRTIO_GPU_F_BLOB_ALIGNMENT, a feature that indicates the device provides a valid blob_alignment field in its configuration, and that both RESOURCE_CREATE_BLOB and RESOURCE_MAP_BLOB requests must be aligned to that value. Signed-off-by: Sergio Lopez Signed-off-by: Dmitry Osipenko Link: https://patch.msgid.link/20260428194450.518296-2-slp@redhat.com --- drivers/gpu/drm/virtio/virtgpu_drv.c | 1 + drivers/gpu/drm/virtio/virtgpu_drv.h | 2 ++ drivers/gpu/drm/virtio/virtgpu_kms.c | 14 +++++++++++--- include/uapi/linux/virtio_gpu.h | 9 +++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index a5ce96fb8a1d..812ee3f5e4aa 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -163,6 +163,7 @@ static unsigned int features[] = { VIRTIO_GPU_F_RESOURCE_UUID, VIRTIO_GPU_F_RESOURCE_BLOB, VIRTIO_GPU_F_CONTEXT_INIT, + VIRTIO_GPU_F_BLOB_ALIGNMENT, }; static struct virtio_driver virtio_gpu_driver = { .feature_table = features, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 6f49213e23f8..04fe15d877cd 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -258,6 +258,7 @@ struct virtio_gpu_device { bool has_resource_blob; bool has_host_visible; bool has_context_init; + bool has_blob_alignment; struct virtio_shm_region host_visible_region; struct drm_mm host_visible_mm; @@ -271,6 +272,7 @@ struct virtio_gpu_device { uint32_t num_capsets; uint64_t capset_id_mask; struct list_head cap_cache; + uint32_t blob_alignment; /* protects uuid state when exporting */ spinlock_t resource_export_lock; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 80ba69b4860b..cfde9f573df6 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -124,7 +124,7 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) struct virtio_gpu_device *vgdev; /* this will expand later */ struct virtqueue *vqs[2]; - u32 num_scanouts, num_capsets; + u32 num_scanouts, num_capsets, blob_alignment; int ret = 0; if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) @@ -198,14 +198,22 @@ int virtio_gpu_init(struct virtio_device *vdev, struct drm_device *dev) if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_CONTEXT_INIT)) vgdev->has_context_init = true; + if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_BLOB_ALIGNMENT)) { + vgdev->has_blob_alignment = true; + virtio_cread_le(vgdev->vdev, struct virtio_gpu_config, + blob_alignment, &blob_alignment); + vgdev->blob_alignment = blob_alignment; + } + DRM_INFO("features: %cvirgl %cedid %cresource_blob %chost_visible", vgdev->has_virgl_3d ? '+' : '-', vgdev->has_edid ? '+' : '-', vgdev->has_resource_blob ? '+' : '-', vgdev->has_host_visible ? '+' : '-'); - DRM_INFO("features: %ccontext_init\n", - vgdev->has_context_init ? '+' : '-'); + DRM_INFO("features: %ccontext_init %cblob_alignment\n", + vgdev->has_context_init ? '+' : '-', + vgdev->has_blob_alignment ? '+' : '-'); ret = virtio_find_vqs(vgdev->vdev, 2, vqs, vqs_info, NULL); if (ret) { diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index be109777d10d..4f530d90058c 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -64,6 +64,14 @@ * context_init and multiple timelines */ #define VIRTIO_GPU_F_CONTEXT_INIT 4 +/* + * The device provides a valid blob_alignment + * field in its configuration and both + * VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB and + * VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB requests + * must be aligned to that value. + */ +#define VIRTIO_GPU_F_BLOB_ALIGNMENT 5 enum virtio_gpu_ctrl_type { VIRTIO_GPU_UNDEFINED = 0, @@ -365,6 +373,7 @@ struct virtio_gpu_config { __le32 events_clear; __le32 num_scanouts; __le32 num_capsets; + __le32 blob_alignment; }; /* simple formats for fbcon/X use */ -- cgit v1.2.3 From 6bd7e82e26531541a6023f060ba749547b9868ac Mon Sep 17 00:00:00 2001 From: Sergio Lopez Date: Tue, 28 Apr 2026 21:44:50 +0200 Subject: drm/virtio: add VIRTGPU_PARAM_BLOB_ALIGNMENT to params Add VIRTGPU_PARAM_BLOB_ALIGNMENT as a param that can be read with VIRTGPU_GETPARAM by userspace applications running in the guest to obtain the host's page size and find out the right alignment to be used in shared memory allocations. Signed-off-by: Sergio Lopez Signed-off-by: Dmitry Osipenko Link: https://patch.msgid.link/20260428194450.518296-4-slp@redhat.com --- drivers/gpu/drm/virtio/virtgpu_ioctl.c | 5 +++++ include/uapi/drm/virtgpu_drm.h | 1 + 2 files changed, 6 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c index 85e2fafe4152..3d8e4ccdb7c1 100644 --- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c +++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c @@ -117,6 +117,11 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data, case VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME: value = vgdev->has_context_init ? 1 : 0; break; + case VIRTGPU_PARAM_BLOB_ALIGNMENT: + if (!vgdev->has_blob_alignment) + return -ENOENT; + value = vgdev->blob_alignment; + break; default: return -EINVAL; } diff --git a/include/uapi/drm/virtgpu_drm.h b/include/uapi/drm/virtgpu_drm.h index ba09a4ee3e77..95587e12aed5 100644 --- a/include/uapi/drm/virtgpu_drm.h +++ b/include/uapi/drm/virtgpu_drm.h @@ -98,6 +98,7 @@ struct drm_virtgpu_execbuffer { #define VIRTGPU_PARAM_CONTEXT_INIT 6 /* DRM_VIRTGPU_CONTEXT_INIT */ #define VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs 7 /* Bitmask of supported capability set ids */ #define VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME 8 /* Ability to set debug name from userspace */ +#define VIRTGPU_PARAM_BLOB_ALIGNMENT 9 /* Device alignment requirements for blobs */ struct drm_virtgpu_getparam { __u64 param; -- cgit v1.2.3 From b397cc489ae42c753c608cddd2dd6e9c2b2d86c0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 27 Apr 2026 11:44:54 -0700 Subject: drm/tegra: tegra_drm.h: fix all uapi kernel-doc warnings Add 2 struct member descriptions and convert #define macro constants comments to kernel-doc comments to eliminate all kernel-doc warnings: Warning: include/uapi/drm/tegra_drm.h:353 struct member 'cmdbuf' not described in 'drm_tegra_reloc' Warning: include/uapi/drm/tegra_drm.h:353 struct member 'target' not described in 'drm_tegra_reloc' Warning: include/uapi/drm/tegra_drm.h:780 This comment starts with '/**', but isn't a kernel-doc comment. * Specify that bit 39 of the patched-in address should be set to switch Warning: include/uapi/drm/tegra_drm.h:832 This comment starts with '/**', but isn't a kernel-doc comment. * Execute `words` words of Host1x opcodes specified in the `gather_data_ptr` Warning: include/uapi/drm/tegra_drm.h:837 This comment starts with '/**', but isn't a kernel-doc comment. * Wait for a syncpoint to reach a value before continuing with further Warning: include/uapi/drm/tegra_drm.h:842 This comment starts with '/**', but isn't a kernel-doc comment. * Wait for a syncpoint to reach a value before continuing with further Signed-off-by: Randy Dunlap Acked-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patch.msgid.link/20260427184454.693794-1-rdunlap@infradead.org --- include/uapi/drm/tegra_drm.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include/uapi') diff --git a/include/uapi/drm/tegra_drm.h b/include/uapi/drm/tegra_drm.h index 94cfc306d50a..8f21f3a44832 100644 --- a/include/uapi/drm/tegra_drm.h +++ b/include/uapi/drm/tegra_drm.h @@ -304,6 +304,7 @@ struct drm_tegra_cmdbuf { * struct drm_tegra_reloc - GEM object relocation structure */ struct drm_tegra_reloc { + /** @cmdbuf: cmd information */ struct { /** * @cmdbuf.handle: @@ -321,6 +322,7 @@ struct drm_tegra_reloc { */ __u32 offset; } cmdbuf; + /** @target: relocate target information */ struct { /** * @target.handle: @@ -778,6 +780,9 @@ struct drm_tegra_channel_unmap { /* Submission */ /** + * define DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT - \ + * Select sector layout swizzling for in-memory buffers. + * * Specify that bit 39 of the patched-in address should be set to switch * swizzling between Tegra and non-Tegra sector layout on systems that store * surfaces in system memory in non-Tegra sector layout. @@ -830,16 +835,27 @@ struct drm_tegra_submit_buf { }; /** + * define DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR - \ + * Execute Host1x opcodes from user pointer. + * * Execute `words` words of Host1x opcodes specified in the `gather_data_ptr` * buffer. Each GATHER_UPTR command uses successive words from the buffer. */ #define DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR 0 + /** + * define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT - \ + * Wait for syncpoint (absolute). + * * Wait for a syncpoint to reach a value before continuing with further * commands. */ #define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT 1 + /** + * define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT_RELATIVE - \ + * Wait for syncpoint (relative). + * * Wait for a syncpoint to reach a value before continuing with further * commands. The threshold is calculated relative to the start of the job. */ -- cgit v1.2.3 From a7b378c949373b6bb4c5a89ffc53085736959dcf Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 26 May 2026 07:50:47 -0700 Subject: 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 Reviewed-by: Anna Maniscalco Reviewed-by: Akhil P Oommen Patchwork: https://patchwork.freedesktop.org/patch/728217/ Message-ID: <20260526145137.160554-14-robin.clark@oss.qualcomm.com> --- drivers/gpu/drm/msm/msm_drv.c | 1 + drivers/gpu/drm/msm/msm_drv.h | 2 + drivers/gpu/drm/msm/msm_gpu.h | 3 + drivers/gpu/drm/msm/msm_perfcntr.c | 529 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_perfcntr.h | 51 ++++ include/uapi/drm/msm_drm.h | 48 ++++ 6 files changed, 634 insertions(+) (limited to 'include/uapi') diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 66322eab7890..79f78e7e16e9 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -801,6 +801,7 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_CLOSE, msm_ioctl_submitqueue_close, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_SUBMITQUEUE_QUERY, msm_ioctl_submitqueue_query, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_VM_BIND, msm_ioctl_vm_bind, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_PERFCNTR_CONFIG, msm_ioctl_perfcntr_config, DRM_RENDER_ALLOW), }; static void msm_show_fdinfo(struct drm_printer *p, struct drm_file *file) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index f00b2e7aeb91..204e140ac8e9 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -237,6 +237,8 @@ int msm_ioctl_vm_bind(struct drm_device *dev, void *data, int msm_perfcntr_resume(struct msm_gpu *gpu); void msm_perfcntr_suspend(struct msm_gpu *gpu); +int msm_ioctl_perfcntr_config(struct drm_device *dev, void *data, + struct drm_file *file); struct msm_perfcntr_state * msm_perfcntr_init(struct msm_gpu *gpu); void msm_perfcntr_cleanup(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index ac124d562037..c9c9a3b75b68 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -353,6 +353,9 @@ struct msm_perfcntr_state { /** @stream: current global counter stream if active */ struct msm_perfcntr_stream *stream; + /** @sel_seqno: counter for sel_fence */ + uint32_t sel_seqno; + /** * @groups: Global perfcntr stream group state. * diff --git a/drivers/gpu/drm/msm/msm_perfcntr.c b/drivers/gpu/drm/msm/msm_perfcntr.c index aeea60cd002e..0a6f8039f610 100644 --- a/drivers/gpu/drm/msm/msm_perfcntr.c +++ b/drivers/gpu/drm/msm/msm_perfcntr.c @@ -3,13 +3,44 @@ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include "drm/drm_file.h" +#include "drm/msm_drm.h" + +#include "linux/anon_inodes.h" +#include "linux/gfp_types.h" +#include "linux/poll.h" +#include "linux/slab.h" + #include "msm_drv.h" #include "msm_gpu.h" #include "msm_perfcntr.h" +#include "adreno/adreno_gpu.h" + +/* space used: */ +#define fifo_count(stream) \ + (CIRC_CNT((stream)->fifo.head, (stream)->fifo.tail, (stream)->fifo_size)) +#define fifo_count_to_end(stream) \ + (CIRC_CNT_TO_END(smp_load_acquire(&(stream)->fifo.head), (stream)->fifo.tail, (stream)->fifo_size)) +/* space available: */ +#define fifo_space(stream) \ + (CIRC_SPACE((stream)->fifo.head, (stream)->fifo.tail, (stream)->fifo_size)) + static int msm_perfcntr_resume_locked(struct msm_perfcntr_stream *stream) { + if (!stream) + return 0; + + /* Reprogram SEL regs on highest priority rb: */ + struct msm_ringbuffer *ring = stream->gpu->rb[0]; + + queue_work(ring->sched.submit_wq, &stream->sel_work); + + hrtimer_start(&stream->sample_timer, + ns_to_ktime(stream->sample_period_ns), + HRTIMER_MODE_REL_PINNED); + return 0; } @@ -25,6 +56,22 @@ msm_perfcntr_resume(struct msm_gpu *gpu) static void msm_perfcntr_suspend_locked(struct msm_perfcntr_stream *stream) { + if (!stream) + return; + + hrtimer_cancel(&stream->sample_timer); + kthread_cancel_work_sync(&stream->sample_work); + + /* + * We can't use cancel_work_sync() here, since sel_work acquires + * gpu->lock which (a) in suspend path can already be held, or + * (b) in release path would invert the order of gpu->lock and + * gpu->perfcntr_lock. Either would cause deadlock. + */ + cancel_work(&stream->sel_work); + + stream->sel_fence = ++stream->gpu->perfcntrs->sel_seqno; + stream->seqno = 0; } void @@ -36,6 +83,488 @@ msm_perfcntr_suspend(struct msm_gpu *gpu) msm_perfcntr_suspend_locked(gpu->perfcntrs->stream); } +static int +msm_perfcntrs_stream_release(struct inode *inode, struct file *file) +{ + struct msm_perfcntr_stream *stream = file->private_data; + struct msm_gpu *gpu = stream->gpu; + + scoped_guard (mutex, &gpu->perfcntr_lock) { + struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs; + + msm_perfcntr_suspend_locked(stream); + perfcntrs->stream = NULL; + + /* release previously allocated counters: */ + for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++) + perfcntrs->groups[i]->allocated_counters = 0; + } + + /* + * In the suspend path we use async cancel_work(), to avoid blocking + * on sel_work, which acquires gpu->lock (which could deadlock since + * other paths acquire gpu->lock before perfcntr_lock) or already + * hold gpu->lock. + * + * But since we are freeing the stream, after dropping perfcntr_lock + * we need to block until sel_work is done: + */ + cancel_work_sync(&stream->sel_work); + + kfree(stream->group_idx); + kfree(stream->fifo.buf); + kfree(stream); + + return 0; +} + +static __poll_t +msm_perfcntrs_stream_poll(struct file *file, poll_table *wait) +{ + struct msm_perfcntr_stream *stream = file->private_data; + __poll_t events = 0; + + poll_wait(file, &stream->poll_wq, wait); + + /* Are there samples to read? */ + if (fifo_count(stream) > 0) + events |= EPOLLIN; + + return events; +} + +static ssize_t +msm_perfcntrs_stream_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct msm_perfcntr_stream *stream = file->private_data; + int ret; + + if (!(file->f_flags & O_NONBLOCK)) { + ret = wait_event_interruptible(stream->poll_wq, + fifo_count(stream) > 0); + if (ret) + return ret; + } + + guard(mutex)(&stream->read_lock); + + struct circ_buf *fifo = &stream->fifo; + const char *fptr = &fifo->buf[fifo->tail]; + + count = min_t(size_t, count, fifo_count_to_end(stream)); + if (!count) + return -EAGAIN; + if (copy_to_user(buf, fptr, count)) + return -EFAULT; + + smp_store_release(&fifo->tail, (fifo->tail + count) & (stream->fifo_size - 1)); + *ppos += count; + + return count; +} + +static const struct file_operations stream_fops = { + .owner = THIS_MODULE, + .release = msm_perfcntrs_stream_release, + .poll = msm_perfcntrs_stream_poll, + .read = msm_perfcntrs_stream_read, +}; + +static void +sel_worker(struct work_struct *w) +{ + struct msm_perfcntr_stream *stream = + container_of(w, typeof(*stream), sel_work); + struct msm_gpu *gpu = stream->gpu; + /* Reprogram SEL regs on highest priority rb: */ + struct msm_ringbuffer *ring = stream->gpu->rb[0]; + + /* + * If in the process of resuming, wait for that. Otherwise sel_worker + * which is enqueued in the resume path can be scheduled before the + * resume completes. + */ + pm_runtime_barrier(&gpu->pdev->dev); + + /* + * sel_work could end up scheduled before suspend, but running + * after. See msm_perfcntr_suspend_locked() + * + * So if we end up running sel_work after the GPU is already + * suspended, just bail. It will be scheduled again after + * the GPU is resumed. + */ + if (!pm_runtime_get_if_active(&gpu->pdev->dev)) + return; + + scoped_guard (mutex, &gpu->lock) { + guard(mutex)(&gpu->perfcntr_lock); + + if (stream == gpu->perfcntrs->stream) { + msm_gpu_hw_init(gpu); + gpu->funcs->perfcntr_configure(gpu, ring, stream); + } + } + + pm_runtime_put_autosuspend(&gpu->pdev->dev); +} + +static void +sample_write(struct msm_perfcntr_stream *stream, int *head, const void *buf, size_t sz) +{ + /* + * FIFO size is power-of-two, and guaranteed to have enough space to + * fit what we are writing. So we should not hit the wrap-around + * point writing things that are power-of-two sized + */ + WARN_ON(CIRC_SPACE_TO_END(*head, stream->fifo.tail, stream->fifo_size) < sz); + + memcpy(&stream->fifo.buf[*head], buf, sz); + + /* Advance head, wrapping around if necessary: */ + *head = (*head + sz) & (stream->fifo_size - 1); +} + +static void +sample_write_u32(struct msm_perfcntr_stream *stream, int *head, uint32_t val) +{ + sample_write(stream, head, &val, sizeof(val)); +} + +static void +sample_write_u64(struct msm_perfcntr_stream *stream, int *head, uint64_t val) +{ + sample_write(stream, head, &val, sizeof(val)); +} + +static void +sample_worker(struct kthread_work *work) +{ + struct msm_perfcntr_stream *stream = + container_of(work, typeof(*stream), sample_work); + struct msm_gpu *gpu = stream->gpu; + struct msm_rbmemptrs *memptrs = gpu->rb[0]->memptrs; + + if (memptrs->perfcntr_fence != stream->sel_fence) + return; + + /* + * Ensure we have enough space to capture a sample period's + * worth of data: + */ + if (stream->period_size > fifo_space(stream)) { + stream->seqno = 0; + return; + } + + if (gpu->funcs->perfcntr_flush) + gpu->funcs->perfcntr_flush(gpu); + + /* Keep local copy of head to avoid updating fifo until the end: */ + int head = stream->fifo.head; + + /* + * We expect the GPU to be powered at this point, as the timer + * and kthread work are canceled/flushed in the suspend path: + */ + sample_write_u64(stream, &head, + to_adreno_gpu(gpu)->funcs->get_timestamp(gpu)); + sample_write_u32(stream, &head, stream->seqno++); + sample_write_u32(stream, &head, 0); + + for (unsigned i = 0; i < stream->nr_groups; i++) { + unsigned group_idx = msm_perfcntr_group_idx(stream, i); + unsigned base = msm_perfcntr_counter_base(stream, group_idx); + + const struct msm_perfcntr_group *group = + &gpu->perfcntr_groups[group_idx]; + + struct msm_perfcntr_group_state *group_state = + gpu->perfcntrs->groups[group_idx]; + + unsigned nr = group_state->allocated_counters; + for (unsigned j = 0; j < nr; j++) { + const struct msm_perfcntr_counter *counter = + &group->counters[j + base]; + uint64_t val = gpu_read64(gpu, counter->counter_reg_lo); + sample_write_u64(stream, &head, val); + } + } + + smp_store_release(&stream->fifo.head, head); + wake_up_all(&stream->poll_wq); +} + +static enum hrtimer_restart +sample_timer(struct hrtimer *hrtimer) +{ + struct msm_perfcntr_stream *stream = + container_of(hrtimer, typeof(*stream), sample_timer); + + kthread_queue_work(stream->gpu->worker, &stream->sample_work); + + hrtimer_forward_now(hrtimer, ns_to_ktime(stream->sample_period_ns)); + + return HRTIMER_RESTART; +} + +static int +get_group_idx(struct msm_gpu *gpu, const char *name, size_t len) +{ + for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++) { + const struct msm_perfcntr_group *group = + &gpu->perfcntr_groups[i]; + if (!strncmp(group->name, name, len)) + return i; + } + + return -1; +} + +static int +get_available_counters(struct msm_gpu *gpu, int group_idx, uint32_t flags) +{ + struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs; + + /* + * For local counter reservation, anything that is not used by + * global perfcntr stream is available: + */ + if (!(flags & MSM_PERFCNTR_STREAM)) { + return gpu->perfcntr_groups[group_idx].num_counters - + perfcntrs->groups[group_idx]->allocated_counters; + } + + /* + * For global counter collection, anything that is not reserved by + * one or more contexts is available: + */ + guard(mutex)(&gpu->dev->filelist_mutex); + + unsigned reserved_counters = 0; + struct drm_file *file; + + list_for_each_entry (file, &gpu->dev->filelist, lhead) { + struct msm_context *ctx = file->driver_priv; + + if (!ctx || !ctx->perfctx) + continue; + + unsigned n = ctx->perfctx->reserved_counters[group_idx]; + reserved_counters = max(reserved_counters, n); + } + + return gpu->perfcntr_groups[group_idx].num_counters - reserved_counters; +} + +int +msm_ioctl_perfcntr_config(struct drm_device *dev, void *data, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + const struct drm_msm_perfcntr_config *args = data; + struct msm_context *ctx = file->driver_priv; + struct msm_gpu *gpu = priv->gpu; + int stream_fd = 0; + + if (!gpu || !gpu->num_perfcntr_groups) + return -ENXIO; + + struct msm_perfcntr_state *perfcntrs = gpu->perfcntrs; + + /* + * Validate args that don't require locks/power first: + */ + + if (args->flags & ~MSM_PERFCNTR_FLAGS) + return UERR(EINVAL, dev, "invalid flags"); + + if (args->nr_groups && !args->group_stride) + return UERR(EINVAL, dev, "invalid group_stride"); + + if (args->nr_groups > gpu->num_perfcntr_groups) + return UERR(EINVAL, dev, "too many groups"); + + if (args->nr_groups && !args->groups) + return UERR(EINVAL, dev, "no groups"); + + if (args->flags & MSM_PERFCNTR_STREAM) { + if (!perfmon_capable()) + return UERR(EPERM, dev, "invalid permissions"); + if (!args->nr_groups) + return UERR(EINVAL, dev, "invalid nr_groups"); + if (!args->period) + return UERR(EINVAL, dev, "invalid sampling period"); + if (args->bufsz_shift > const_ilog2(SZ_128M)) + return UERR(EINVAL, dev, "buffer size too big (>128M)"); + } else { + if (args->period) + return UERR(EINVAL, dev, "sampling period not allowed"); + if (args->bufsz_shift) + return UERR(EINVAL, dev, "sample buf size not allowed"); + } + + /* + * To avoid iterating over the groups multiple times, allocate and setup + * both a ctx and global stream object. Only one of the two will be + * kept in the end. + */ + + struct msm_perfcntr_context_state *perfctx __free(kfree) = kzalloc( + struct_size(perfctx, reserved_counters, gpu->num_perfcntr_groups), + GFP_KERNEL); + if (!perfctx) + return -ENOMEM; + + struct msm_perfcntr_stream *stream __free(kfree) = kzalloc_obj(*stream); + if (!stream) + return -ENOMEM; + + uint8_t *nr_counters __free(kfree) = kzalloc_objs(uint8_t, gpu->num_perfcntr_groups); + if (!nr_counters) + return -ENOMEM; + + uint32_t *group_idx __free(kfree) = kzalloc_objs(uint32_t, args->nr_groups); + if (!group_idx) + return -ENOMEM; + + stream->gpu = gpu; + stream->sample_period_ns = args->period; + stream->nr_groups = args->nr_groups; + stream->fifo_size = 1ull << args->bufsz_shift; + + mutex_init(&stream->read_lock); + + guard(mutex)(&gpu->perfcntr_lock); + + if (args->flags & MSM_PERFCNTR_STREAM) { + if (perfcntrs->stream) + return UERR(EBUSY, dev, "perfcntr stream already open"); + } + + size_t bufsz = 16; /* header size includes seqno and 64b timestamp: */ + int ret = 0; + + for (unsigned i = 0; i < args->nr_groups; i++) { + struct drm_msm_perfcntr_group g = {0}; + size_t sz = min_t(size_t, args->group_stride, sizeof(g)); + void __user *userptr = + u64_to_user_ptr(args->groups + (i * args->group_stride)); + + if (copy_from_user(&g, userptr, sz)) + return -EFAULT; + + if (g.pad) + return UERR(EINVAL, dev, "groups[%d]: invalid pad", i); + + int idx = get_group_idx(gpu, g.group_name, sizeof(g.group_name)); + + if (idx < 0) + return UERR(EINVAL, dev, "groups[%d]: unknown group", i); + + if (nr_counters[idx]) + return UERR(EINVAL, dev, "groups[%d]: duplicate group", i); + + if (g.nr_countables > gpu->perfcntr_groups[idx].num_counters) + return UERR(EINVAL, dev, "groups[%d]: too many counters", i); + + if (args->flags & MSM_PERFCNTR_STREAM) { + if (g.nr_countables && !g.countables) + return UERR(EINVAL, dev, "groups[%d]: no countables", i); + } else { + if (g.countables) + return UERR(EINVAL, dev, "groups[%d]: countables should be NULL", i); + } + + int avail_counters = get_available_counters(gpu, idx, args->flags); + if (g.nr_countables > avail_counters) { + /* + * Defer error return until we process all groups, in + * case there are other E2BIG groups: + */ + ret = UERR(E2BIG, dev, "groups[%d]: too few counters available", i); + + if (args->flags & MSM_PERFCNTR_UPDATE) { + /* Let userspace know how many counters are actually avail: */ + g.nr_countables = avail_counters; + if (copy_to_user(userptr, &g, sz)) + return -EFAULT; + } + } + + group_idx[i] = idx; + perfctx->reserved_counters[idx] = g.nr_countables; + + /* +1 to catch duplicate zero sized groups: */ + nr_counters[idx] = g.nr_countables + 1; + + if (args->flags & MSM_PERFCNTR_STREAM) { + size_t sz = sizeof(uint32_t) * g.nr_countables; + void __user *userptr = u64_to_user_ptr(g.countables); + + if (copy_from_user(perfcntrs->groups[idx]->countables, userptr, sz)) + return -EFAULT; + + /* Samples are 64b per countable: */ + bufsz += 2 * sz; + } + } + + if (ret) + return ret; + + if (args->flags & MSM_PERFCNTR_STREAM) { + /* + * Validate requested buffer size is large enough for at least + * a single sample period. + * + * Note the circ_buf implementation needs to be 1 byte larger + * than max it can hold (see CIRC_SPACE()). + */ + if (stream->fifo_size <= bufsz) + return UERR(EINVAL, dev, "required buffer size: %zu", bufsz); + + /* There aren't enough counters to hit this limit: */ + WARN_ON(bufsz > SZ_128M); + + stream->period_size = bufsz; + + void *buf __free(kfree) = kmalloc(stream->fifo_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + FD_PREPARE(fdf, O_CLOEXEC, + anon_inode_getfile("[msm_perfcntrs]", &stream_fops, stream, 0)); + if (fdf.err) + return fdf.err; + + INIT_WORK(&stream->sel_work, sel_worker); + kthread_init_work(&stream->sample_work, sample_worker); + init_waitqueue_head(&stream->poll_wq); + hrtimer_setup(&stream->sample_timer, sample_timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + + stream->sel_fence = ++perfcntrs->sel_seqno; + stream->group_idx = no_free_ptr(group_idx); + stream->fifo.buf = no_free_ptr(buf); + + /* commit the allocated counters, subtracting off original +1: */ + for (unsigned i = 0; i < gpu->num_perfcntr_groups; i++) + perfcntrs->groups[i]->allocated_counters = nr_counters[i] - 1; + + perfcntrs->stream = no_free_ptr(stream); + + msm_perfcntr_resume_locked(perfcntrs->stream); + + stream_fd = fd_publish(fdf); + } else { + kfree(ctx->perfctx); + ctx->perfctx = no_free_ptr(perfctx); + } + + return stream_fd; +} + /** * msm_perfcntr_group_idx - map idx of perfcntr group to group_idx * @stream: The global perfcntr stream diff --git a/drivers/gpu/drm/msm/msm_perfcntr.h b/drivers/gpu/drm/msm/msm_perfcntr.h index 2ceedec5296b..0feeb81c531f 100644 --- a/drivers/gpu/drm/msm/msm_perfcntr.h +++ b/drivers/gpu/drm/msm/msm_perfcntr.h @@ -7,6 +7,11 @@ #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" @@ -42,12 +47,49 @@ 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 * @@ -56,6 +98,15 @@ struct msm_perfcntr_stream { * 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); diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index b99098792371..7f2e594be4eb 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -491,6 +491,52 @@ struct drm_msm_submitqueue_query { __u32 pad; }; +#define MSM_PERFCNTR_STREAM 0x00000001 +#define MSM_PERFCNTR_UPDATE 0x00000002 +#define MSM_PERFCNTR_FLAGS ( \ + MSM_PERFCNTR_STREAM | \ + MSM_PERFCNTR_UPDATE | \ + 0) + +struct drm_msm_perfcntr_group { + char group_name[16]; + __u32 nr_countables; + __u32 pad; /* mbz */ + __u64 countables; /* pointer to an array of nr_countables u32 */ +}; + +/* + * Note, for MSM_PERFCNTR_STREAM, the ioctl returns an fd to read recorded + * counters. This only works because the ioctl is DRM_IOW(), if we returned + * a out param in the ioctl struct the copy_to_user() (in drm_ioctl()) + * could fault, causing us to leak the fd. + * + * If the ioctl returns with error E2BIG, that means more counters/countables + * are requested than are currently available. If MSM_PERFCNTR_UPDATE flag + * is set, drm_msm_perfcntr_group::nr_countables will be updated to return + * the actual # of counters available. + * + * The data read from the has the following format for each sampling period: + * + * uint64_t timestamp; // CP_ALWAYS_ON_COUNTER captured at sample time + * uint32_t seqno; // increments by 1 each period, reset to 0 on discontinuity + * uint32_t mbz; // pad out counters to 64b + * struct { + * uint64_t counter[nr_countables]; + * } groups[nr_groups]; + * + * The ordering of groups and counters matches the order in PERFCNTR_CONFIG + * ioctl. + */ +struct drm_msm_perfcntr_config { + __u32 flags; /* bitmask of MSM_PERFCNTR_x */ + __u32 nr_groups; /* # of entries in groups array */ + __u64 groups; /* pointer to array of drm_msm_perfcntr_group */ + __u64 period; /* sampling period in ns */ + __u32 bufsz_shift; /* sample buffer size in bytes is 1<