drm/panthor: Add Mali v15 virtualization support
Subsystems (6)
v2 cover drm/panthor: Add Mali v15 virtualization support
This series adds HW-assisted para-virtualization support for Mali v15 GPUs. v15 GPUs provide 16 register sets for job submission known as access windows (AWs). The GPU hardware itself is then time-sliced across each requesting access window.
v2:
- Rebased on drm-misc-next and collected R-bs.
- Moved the Mali 5th-Gen AM GPU binding to a separate schema.
Extended the AM system and arbitration bindings to describe
resource assignments for GPUs that support partitioning.
- Corrected neural accelerator and GPU ID naming. Preserved GPU ID
log output for older GPUs and fixed MMU interrupt initialization.
- Fixed runtime PM rollback and driver cleanup. Protected register
access from shared IRQ handlers while the hardware is powered off.
- Strengthened AM protocol-version checks. Reworked message retries, arbitration command retries and timeout handling.
- Protected access-window assignments with a lock and saved requests received before assignment. Assigned all access windows to
partition 0 when its mask is absent or zero.
- Reworked access-window request, grant and yield handling. Resent
pending GPU requests after an arbiter restart.
- Stopped scheduler tick work before system suspend. Fixed resume
retries, autosuspend after yield and cleanup during device removal.
- Improved handling of GPU access loss during firmware waits and
reset. Cleared stale software reset state on resume.
- Added partition recovery during probe to ensure partitions reach
RESET before arbitration starts.
- Bumped the DRM version to 1.10 for the extended gpu_info fields.
- Link to v1: https://lore.kernel.org/all/[email protected]/
v1:
- Rebased on drm-misc-next.
- Added device-tree bindings for the GPU and virtualization components.
- Improved GPU identification and register handling.
- Updated AM messaging to protocol v2.
- Improved GPU scheduling and recovery from timeouts and failed
commands.
- Added access-window assignments through device tree and earlier GPU release when another window is waiting.
- Improved power management, driver setup and cleanup.
- Fixed races involving GPU resets, loss of access and late grants.
- Kept frequency reporting available without devfreq and documented scheduler timeout settings.
- Link to RFC: https://lore.kernel.org/all/[email protected]/
Karunika Choo (28):
drm/panthor: Ignore -EOPNOTSUPP for shader-present nvmem lookup drm/panthor: Rename neural accelerator feature macro to NX drm/panthor: Move register access helpers out of panthor_device.h drm/panthor: Parse and store GPU_ID fields
drm/panthor: Add 64-bit GPU_ID decoding for v15 GPUs drm/panthor: Move register base offsets to the HW description drm/panthor: Derive MMU AS register addresses from base and stride
dt-bindings: gpu: mali-gen5-am: Add Mali 5th-Gen AM schema drm/panthor: Add Mali v15 hardware support
drm/panthor: Skip devfreq when no OPP table is present
dt-bindings: gpu: panthor: Document AM system bindings drm/panthor: Add AM_SYSTEM platform driver
dt-bindings: gpu: panthor: Document panthor-arbitration bindings drm/panthor: Add AM_PARTITION_CONTROL support drm/panthor: Add AM message helpers
drm/panthor: Add AM_RESOURCE_GROUP support
drm/panthor: Add arbitration scheduler
drm/panthor: Route arbitration events
drm/panthor: Add AW assignment tracking
drm/panthor: Handle partition control INVALID_COMMAND interrupt drm/panthor: Request AW to yield GPU access on idle drm/panthor: Add access-window support
drm/panthor: Synchronize HW component PM transitions drm/panthor: Quiesce scheduler tick during system suspend drm/panthor: Route HW component PM through access windows drm/panthor: Tolerate access-window loss during HW waits drm/panthor: Prevent missed post-yield cleanup due to reset drm/panthor: Reset partitions before starting arbitration
.../testing/sysfs-driver-panthor-arbitration | 18 + .../gpu/arm,mali-gen5-am-arbitration.yaml | 198 ++++ .../bindings/gpu/arm,mali-gen5-am-system.yaml | 196 ++++ .../bindings/gpu/arm,mali-gen5-am.yaml | 90 ++ MAINTAINERS | 2 + drivers/gpu/drm/panthor/Kconfig | 20 + drivers/gpu/drm/panthor/Makefile | 3 + drivers/gpu/drm/panthor/arbitration/Makefile | 15 + .../panthor/arbitration/panthor_arbitration.h | 73 ++ .../arbitration/panthor_arbitration_drv.c | 451 +++++++++ .../arbitration/panthor_arbitration_sched.c | 882 ++++++++++++++++++ .../arbitration/panthor_arbitration_sched.h | 45 + .../arbitration/panthor_partition_control.c | 525 +++++++++++ .../arbitration/panthor_partition_control.h | 29 + .../arbitration/panthor_resource_group.c | 373 ++++++++ .../arbitration/panthor_resource_group.h | 20 + drivers/gpu/drm/panthor/panthor_am_msg.h | 182 ++++ drivers/gpu/drm/panthor/panthor_aw.c | 689 ++++++++++++++ drivers/gpu/drm/panthor/panthor_aw.h | 57 ++ drivers/gpu/drm/panthor/panthor_devfreq.c | 29 +- drivers/gpu/drm/panthor/panthor_device.c | 112 ++- drivers/gpu/drm/panthor/panthor_device.h | 146 ++- drivers/gpu/drm/panthor/panthor_device_io.h | 84 ++ drivers/gpu/drm/panthor/panthor_drv.c | 13 +- drivers/gpu/drm/panthor/panthor_fw.c | 27 +- drivers/gpu/drm/panthor/panthor_fw.h | 2 + drivers/gpu/drm/panthor/panthor_fw_regs.h | 2 - drivers/gpu/drm/panthor/panthor_gpu.c | 13 +- .../drm/panthor/panthor_gpu_discover_regs.h | 42 + drivers/gpu/drm/panthor/panthor_gpu_regs.h | 4 +- drivers/gpu/drm/panthor/panthor_heap.c | 3 +- drivers/gpu/drm/panthor/panthor_hw.c | 209 ++++- drivers/gpu/drm/panthor/panthor_hw.h | 59 +- drivers/gpu/drm/panthor/panthor_mmu.c | 47 +- drivers/gpu/drm/panthor/panthor_mmu_regs.h | 23 +- drivers/gpu/drm/panthor/panthor_pwr.c | 36 +- drivers/gpu/drm/panthor/panthor_pwr_regs.h | 2 - drivers/gpu/drm/panthor/panthor_sched.c | 21 + drivers/gpu/drm/panthor/panthor_sched.h | 2 + drivers/gpu/drm/panthor/system/Makefile | 13 + .../drm/panthor/system/panthor_system_drv.c | 344 +++++++ include/uapi/drm/panthor_drm.h | 23 +- 42 files changed, 4939 insertions(+), 185 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-panthor-arbitration create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-arbitration.yaml create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml create mode 100644 drivers/gpu/drm/panthor/arbitration/Makefile create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.h create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_partition_control.h create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_resource_group.h create mode 100644 drivers/gpu/drm/panthor/panthor_am_msg.h create mode 100644 drivers/gpu/drm/panthor/panthor_aw.c create mode 100644 drivers/gpu/drm/panthor/panthor_aw.h create mode 100644 drivers/gpu/drm/panthor/panthor_device_io.h create mode 100644 drivers/gpu/drm/panthor/panthor_gpu_discover_regs.h create mode 100644 drivers/gpu/drm/panthor/system/Makefile create mode 100644 drivers/gpu/drm/panthor/system/panthor_system_drv.c
--
2.43.0
PATCH v2 1/28 drm/panthor: Ignore -EOPNOTSUPP for shader-present nvmem lookup
When CONFIG_NVMEM is disabled, reading the optional "shader-present" nvmem cell can return -EOPNOTSUPP.
Treat this the same as the cell being absent so panthor can continue probing on platforms that do not provide shader-present fuses through nvmem.
---
v2:
- Picked up R-b from Liviu
v1:
- Picked up R-bs from Boris and Steve
- Added Fixes tag
drivers/gpu/drm/panthor/panthor_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/panthor/panthor_hw.c +1 -1
@@ -182,7 +182,7 @@ static int overload_shader_present(struct panthor_device *ptdev) &contents);if (!ret) ptdev->gpu_info.shader_present = contents; -else if (ret == -ENOENT ) +else if (ret == -ENOENT || ret == -EOPNOTSUPP )return 0 ;else return dev_err_probe(ptdev->base.dev, ret,
Signature · 1 line
2.43.0
PATCH v2 2/28 drm/panthor: Rename neural accelerator feature macro to NX
In reply to Karunika ChooRename GPU_FEATURES_NEURAL_ENGINE to GPU_FEATURES_NX. Update the panthor_hw helper to use the new name.
--- drivers/gpu/drm/panthor/panthor_gpu_regs.h | 2 +- drivers/gpu/drm/panthor/panthor_hw.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/panthor/panthor_gpu_regs.h +1 -1
@@ -67,7 +67,7 @@#define GPU_FEATURES 0x60#define GPU_FEATURES_RAY_INTERSECTION BIT(2) -#define GPU_FEATURES_NEURAL_ENGINE BIT(4) +#define GPU_FEATURES_NX BIT(4)#define GPU_FEATURES_RAY_TRAVERSAL BIT(5)#define GPU_TIMESTAMP_OFFSET 0x88
drivers/gpu/drm/panthor/panthor_hw.h +1 -1
@@ -64,7 +64,7 @@ static inline bool panthor_hw_has_pwr_ctrl(struct panthor_device *ptdev)static inline bool panthor_hw_has_neural (struct panthor_device *ptdev) {return (GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id) >=14 && - ptdev->gpu_info.gpu_features &GPU_FEATURES_NEURAL_ENGINE ); + ptdev->gpu_info.gpu_features &GPU_FEATURES_NX ); }#endif /* __PANTHOR_HW_H__ */
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 02/28] drm/panthor: Rename neural accelerator feature macro to NX
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Low] drm/panthor: commit message does not explain why GPU_FEATURES_NX is renamed --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Low] drm/panthor: commit message does not explain why GPU_FEATURES_NX is renamed
--
commit b271181b3f70a8fceddc935ef5d82c1ab9eb1aa8
Author: Karunika Choo <[email protected]>
Quoted 6 lines
drm/panthor: Rename neural accelerator feature macro to NX
Rename
GPU_FEATURES_NEURAL_ENGINEtoGPU_FEATURES_NX. Update thepanthor_hwhelper to use the new name.Signed-off-by Karunika Choo <[email protected]>
[Severity: Low]
This isn't a bug, but the commit message only restates the code change without explaining why GPU_FEATURES_NEURAL_ENGINE is renamed to GPU_FEATURES_NX while panthor_hw_has_neural() and the PWR_NEURAL_* definitions keep the neural naming. Could the commit message explain the rationale for the new name (for example, matching the hardware register specification)?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
PATCH v2 3/28 drm/panthor: Move register access helpers out of panthor_device.h
In reply to Karunika ChooMove register access helpers out of panthor_device.h to allow reuse by other panthor drivers that will be added to enable v15 support.
---
v2:
- Picked up R-b from Liviu
- Fix includes raised by sashiko
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- Includes "panthor_device_io.h" directly in "panthor_device.h" instead of peppering multiple files with the header.
drivers/gpu/drm/panthor/panthor_device.h | 73 +----------------- drivers/gpu/drm/panthor/panthor_device_io.h | 84 +++++++++++++++++++++ 2 files changed, 86 insertions(+), 71 deletions(-) create mode 100644 drivers/gpu/drm/panthor/panthor_device_io.h
drivers/gpu/drm/panthor/panthor_device.h +2 -71
@@ -19,6 +19,8 @@#include <drm/gpu_scheduler.h> #include <drm/panthor_drm.h> +#include "panthor_device_io.h" +struct panthor_csf ;struct panthor_csf_ctx ;struct panthor_device ;
@@ -495,77 +497,6 @@ panthor_exception_is_fault(u32 exception_code)const char *panthor_exception_name (struct panthor_device *ptdev,u32 exception_code); -static inline void gpu_write (void __iomem *iomem,u32 reg,u32 data) -{ -writel (data, iomem + reg); -} - -static inline u32 gpu_read (void __iomem *iomem,u32 reg) -{ -return readl (iomem + reg); -} - -static inline u32 gpu_read_relaxed (void __iomem *iomem,u32 reg) -{ -return readl_relaxed (iomem + reg); -} - -static inline void gpu_write64 (void __iomem *iomem,u32 reg,u64 data) -{ -gpu_write (iomem, reg,lower_32_bits (data)); -gpu_write (iomem, reg +4 ,upper_32_bits (data)); -} - -static inline u64 gpu_read64 (void __iomem *iomem,u32 reg) -{ -return (gpu_read (iomem, reg) | ((u64 )gpu_read (iomem, reg +4 ) <<32 )); -} - -static inline u64 gpu_read64_relaxed (void __iomem *iomem,u32 reg) -{ -return (gpu_read_relaxed (iomem, reg) | - ((u64 )gpu_read_relaxed (iomem, reg +4 ) <<32 )); -} - -static inline u64 gpu_read64_counter (void __iomem *iomem,u32 reg) -{ -u32 lo, hi1, hi2; -do { - hi1 =gpu_read (iomem, reg +4 ); - lo =gpu_read (iomem, reg); - hi2 =gpu_read (iomem, reg +4 ); - }while (hi1 != hi2); -return lo | ((u64 )hi2 <<32 ); -} - -#define gpu_read_poll_timeout (iomem, reg, val, cond, delay_us, timeout_us) \ - read_poll_timeout(gpu_read, val, cond, delay_us, timeout_us, false, \ - iomem, reg) - -#define gpu_read_poll_timeout_atomic (iomem, reg, val, cond, delay_us, \ - timeout_us) \ - read_poll_timeout_atomic(gpu_read, val, cond, delay_us, timeout_us, \ - false, iomem, reg) - -#define gpu_read64_poll_timeout (iomem, reg, val, cond, delay_us, timeout_us) \ - read_poll_timeout(gpu_read64, val, cond, delay_us, timeout_us, false, \ - iomem, reg) - -#define gpu_read64_poll_timeout_atomic (iomem, reg, val, cond, delay_us, \ - timeout_us) \ - read_poll_timeout_atomic(gpu_read64, val, cond, delay_us, timeout_us, \ - false, iomem, reg) - -#define gpu_read_relaxed_poll_timeout_atomic (iomem, reg, val, cond, delay_us, \ - timeout_us) \ - read_poll_timeout_atomic(gpu_read_relaxed, val, cond, delay_us, \ - timeout_us, false, iomem, reg) - -#define gpu_read64_relaxed_poll_timeout (iomem, reg, val, cond, delay_us, \ - timeout_us) \ - read_poll_timeout(gpu_read64_relaxed, val, cond, delay_us, timeout_us, \ - false, iomem, reg) -#define INT_RAWSTAT 0x0#define INT_CLEAR 0x4#define INT_MASK 0x8
drivers/gpu/drm/panthor/panthor_device_io.h new file +84 -0
84 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v2 4/28 drm/panthor: Parse and store GPU_ID fields
In reply to Karunika ChooPrepare for Mali v15, where GPU_ID expands to 64 bits and its field layout changes.
Introduce a small panthor_gpu_id structure and parse the GPU_ID fields once during hardware initialization. Convert existing users to consume the cached fields instead of extracting them repeatedly from the raw register value.
This centralizes GPU_ID decoding and makes it easier to support both the existing and v15 formats.
---
v2:
- Picked up R-b from Liviu
- Avoid modifying the printed id field for existing GPUs.
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- changed struct panthor_gpu_id into a flat structure instead of inconsistent groupings.
drivers/gpu/drm/panthor/panthor_device.h | 29 ++++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_fw.c | 4 ++-- drivers/gpu/drm/panthor/panthor_gpu.c | 2 +- drivers/gpu/drm/panthor/panthor_hw.c | 24 ++++++++++++++------ drivers/gpu/drm/panthor/panthor_hw.h | 4 ++-- 5 files changed, 51 insertions(+), 12 deletions(-)
drivers/gpu/drm/panthor/panthor_device.h +29 -0
@@ -111,6 +111,32 @@ struct panthor_irq {enum panthor_irq_state state; }; +/** +* struct panthor_gpu_id - Parsed GPU_ID fields +*/ +struct panthor_gpu_id { +/** @arch_major: Architecture major revision */ +u8 arch_major; + +/** @arch_minor: Architecture minor revision */ +u8 arch_minor; + +/** @arch_rev: Architecture patch revision */ +u8 arch_rev; + +/** @prod_major: Product identifier */ +u8 prod_major; + +/** @ver_major: Major release version number */ +u8 ver_major; + +/** @ver_minor: Minor release version number */ +u8 ver_minor; + +/** @ver_status: Status of GPU release */ +u8 ver_status; +}; +/** * enum panthor_device_profiling_mode - Profiling state */
@@ -170,6 +196,9 @@ struct panthor_device {/** @mmu_info: MMU info */ struct drm_panthor_mmu_info mmu_info; +/** @gpu_id: Parsed GPU_ID fields */ +struct panthor_gpu_id gpu_id; +/** @hw: GPU-specific data. */ struct panthor_hw *hw;
drivers/gpu/drm/panthor/panthor_fw.c +2 -2
@@ -809,8 +809,8 @@ static int panthor_fw_load(struct panthor_device *ptdev)int ret;snprintf (fw_path,sizeof (fw_path),"arm/mali/arch%d.%d/%s" , - (u32 )GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id), - (u32 )GPU_ARCH_MINOR (ptdev->gpu_info.gpu_id), + (u32 )ptdev->gpu_id.arch_major, + (u32 )ptdev->gpu_id.arch_minor,CSF_FW_NAME ); ret =request_firmware (&fw, fw_path, ptdev->base.dev);
drivers/gpu/drm/panthor/panthor_gpu.c +1 -1
@@ -74,7 +74,7 @@ static void panthor_gpu_l2_config_set(struct panthor_device *ptdev)if (!data || !data->asn_hash_enable)return ; -if (GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id) <11 ) { +if (ptdev->gpu_id.arch_major <11 ) {drm_err (&ptdev->base,"Custom ASN hash not supported by the device" );return ; }
drivers/gpu/drm/panthor/panthor_hw.c +17 -7
@@ -119,9 +119,9 @@ void panthor_hw_power_status_unregister(void)static char *get_gpu_model_name (struct panthor_device *ptdev) { -const u32 gpu_id = ptdev->gpu_info.gpu_id; -const u32 product_id =GPU_PROD_ID_MAKE (GPU_ARCH_MAJOR (gpu_id), -GPU_PROD_MAJOR (gpu_id)); +const struct panthor_gpu_id *gpu_id = &ptdev->gpu_id; +const u32 product_id =GPU_PROD_ID_MAKE (gpu_id->arch_major, + gpu_id->prod_major);const bool ray_intersection = !!(ptdev->gpu_info.gpu_features &GPU_FEATURES_RAY_INTERSECTION );const u8 shader_core_count =hweight64 (ptdev->gpu_info.shader_present);
@@ -245,9 +245,9 @@ static int panthor_hw_info_init(struct panthor_device *ptdev)if (ret)return ret; - major =GPU_VER_MAJOR (ptdev->gpu_info.gpu_id); - minor =GPU_VER_MINOR (ptdev->gpu_info.gpu_id); - status =GPU_VER_STATUS (ptdev->gpu_info.gpu_id); + major = ptdev->gpu_id.ver_major; + minor = ptdev->gpu_id.ver_minor; + status = ptdev->gpu_id.ver_status; drm_info(&ptdev->base, "%s id 0x%x major 0x%x minor 0x%x status 0x%x",
@@ -273,7 +273,7 @@ static int panthor_hw_info_init(struct panthor_device *ptdev)static int panthor_hw_bind_device (struct panthor_device *ptdev) {struct panthor_hw *hdev =NULL ; -const u32 arch_major =GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id); +const u32 arch_major = ptdev->gpu_id.arch_major;int i =0 ;for (i =0 ; i <ARRAY_SIZE (panthor_hw_match); i++) {
@@ -295,10 +295,20 @@ static int panthor_hw_bind_device(struct panthor_device *ptdev)static int panthor_hw_gpu_id_init (struct panthor_device *ptdev) { +struct panthor_gpu_id *gpu_id = &ptdev->gpu_id; ptdev->gpu_info.gpu_id =gpu_read (ptdev->iomem,GPU_ID ); +if (!ptdev->gpu_info.gpu_id)return -ENXIO ; + gpu_id->arch_major =GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id); + gpu_id->arch_minor =GPU_ARCH_MINOR (ptdev->gpu_info.gpu_id); + gpu_id->arch_rev =GPU_ARCH_REV (ptdev->gpu_info.gpu_id); + gpu_id->prod_major =GPU_PROD_MAJOR (ptdev->gpu_info.gpu_id); + gpu_id->ver_major =GPU_VER_MAJOR (ptdev->gpu_info.gpu_id); + gpu_id->ver_minor =GPU_VER_MINOR (ptdev->gpu_info.gpu_id); + gpu_id->ver_status =GPU_VER_STATUS (ptdev->gpu_info.gpu_id); +return 0 ; }
drivers/gpu/drm/panthor/panthor_hw.h +2 -2
@@ -58,12 +58,12 @@ static inline void panthor_hw_l2_power_off(struct panthor_device *ptdev)static inline bool panthor_hw_has_pwr_ctrl (struct panthor_device *ptdev) { -return GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id) >=14 ; +return ptdev->gpu_id.arch_major >=14 ; }static inline bool panthor_hw_has_neural (struct panthor_device *ptdev) { -return (GPU_ARCH_MAJOR (ptdev->gpu_info.gpu_id) >=14 && +return (ptdev->gpu_id.arch_major >=14 && ptdev->gpu_info.gpu_features &GPU_FEATURES_NX ); }
Signature · 1 line
2.43.0
PATCH v2 5/28 drm/panthor: Add 64-bit GPU_ID decoding for v15 GPUs
In reply to Karunika ChooMali v15 exposes a 64-bit GPU_ID register with a different field layout from earlier GPUs.
Add the register definitions and decoding helpers for the new format, read GPU_ID_WIDE when the compatibility value indicates a v15 GPU, and populate both the cached GPU_ID fields and the uAPI gpu_id_wide field.
This allows userspace and the driver to identify v15 GPUs correctly.
---
v2:
- Picked up R-b from Liviu.
- Rename the register macro from GPU_WIDE_ID to GPU_ID_WIDE.
- Rename the uAPI field from gpu_wide_id to gpu_id_wide.
- Print the upper 32 bits of GPU_ID_WIDE as the logged 'id' for v15 and later GPUs. Keep the existing output for earlier GPUs. Continuation fix for previous sashiko comment.
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- Decode selected GPU_ID format after checking compatibility value.
- Document GPU_DISCOVER and GPU_CONTROL register offset differences between GPUs.
- Fix mask generation in panthor_gpu_discover_regs.h
.../drm/panthor/panthor_gpu_discover_regs.h | 19 ++++++ drivers/gpu/drm/panthor/panthor_hw.c | 62 ++++++++++++++----- include/uapi/drm/panthor_drm.h | 13 ++++ 3 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 drivers/gpu/drm/panthor/panthor_gpu_discover_regs.h
drivers/gpu/drm/panthor/panthor_gpu_discover_regs.h new file +19 -0
@@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_GPU_DISCOVER_REGS_H__ +#define __PANTHOR_GPU_DISCOVER_REGS_H__ + +#include <linux/bits.h> + +#define GPU_ID_WIDE 0x0 +#define GPU_WIDE_COMPAT 0xF +#define GPU_WIDE_ARCH_MAJOR (x) (((x) & GENMASK_U64(63, 56)) >> 56) +#define GPU_WIDE_ARCH_MINOR (x) (((x) & GENMASK_U64(55, 48)) >> 48) +#define GPU_WIDE_ARCH_REV (x) (((x) & GENMASK_U64(47, 40)) >> 40) +#define GPU_WIDE_PROD_MAJOR (x) (((x) & GENMASK_U64(39, 32)) >> 32) +#define GPU_WIDE_VER_MAJOR (x) (((x) & GENMASK_U64(23, 16)) >> 16) +#define GPU_WIDE_VER_MINOR (x) (((x) & GENMASK_U64(15, 8)) >> 8) +#define GPU_WIDE_VER_STATUS (x) ((x) & GENMASK_U64(7, 0)) + +#endif /* __PANTHOR_GPU_DISCOVER_REGS_H__ */
drivers/gpu/drm/panthor/panthor_hw.c +48 -14
98 lines not on this page · raw message
include/uapi/drm/panthor_drm.h +13 -0
@@ -376,6 +376,19 @@ struct drm_panthor_gpu_info {/** @gpu_features: Bitmask describing supported GPU-wide features */ __u64 gpu_features; + +/** +* @gpu_id_wide: 64-bit GPU ID for v15 and later GPUs. @gpu_id is 0 when +* this is populated. +*/ +__u64 gpu_id_wide; +#define DRM_PANTHOR_WIDE_ARCH_MAJOR (x) (((x) >> 56) & 0xff) +#define DRM_PANTHOR_WIDE_ARCH_MINOR (x) (((x) >> 48) & 0xff) +#define DRM_PANTHOR_WIDE_ARCH_REV (x) (((x) >> 40) & 0xff) +#define DRM_PANTHOR_WIDE_PRODUCT_MAJOR (x) (((x) >> 32) & 0xff) +#define DRM_PANTHOR_WIDE_VERSION_MAJOR (x) (((x) >> 16) & 0xff) +#define DRM_PANTHOR_WIDE_VERSION_MINOR (x) (((x) >> 8) & 0xff) +#define DRM_PANTHOR_WIDE_VERSION_STATUS (x) ((x) & 0xff) };/**
Signature · 1 line
2.43.0
PATCH v2 6/28 drm/panthor: Move register base offsets to the HW description
In reply to Karunika ChooMali v15 reorders several register regions, including GPU_CONTROL, MCU_CONTROL and PWR_CONTROL, so the driver can no longer assume a single fixed base layout across all supported GPUs.
Add per-GPU register base offsets to the panthor hardware description and switch the GPU, FW and PWR local iomem setup to use those stored values. With the base addresses now owned by the hardware description, drop the corresponding fixed base-offset definitions from the register headers.
This prepares the driver for GPUs with different register layouts without changing the existing behaviour on currently supported parts.
---
v2:
- Picked up R-b from Liviu
v1:
- rebased on drm-misc-next
- use a generic panthor_hw_regbank structure for all register offsets.
drivers/gpu/drm/panthor/panthor_fw.c | 2 +- drivers/gpu/drm/panthor/panthor_fw_regs.h | 2 -- drivers/gpu/drm/panthor/panthor_gpu.c | 4 +-- drivers/gpu/drm/panthor/panthor_gpu_regs.h | 2 -- drivers/gpu/drm/panthor/panthor_hw.c | 23 +++++++++++++++-- drivers/gpu/drm/panthor/panthor_hw.h | 29 ++++++++++++++++++++-- drivers/gpu/drm/panthor/panthor_pwr.c | 2 +- drivers/gpu/drm/panthor/panthor_pwr_regs.h | 2 -- 8 files changed, 52 insertions(+), 14 deletions(-)
drivers/gpu/drm/panthor/panthor_fw.c +1 -1
@@ -1500,7 +1500,7 @@ int panthor_fw_init(struct panthor_device *ptdev)if (!fw)return -ENOMEM ; - fw->iomem = ptdev->iomem +MCU_CONTROL_BASE ; + fw->iomem = ptdev->iomem + ptdev->hw->regs.mcu_control.offset; ptdev->fw = fw;init_waitqueue_head (&fw->req_waitqueue);INIT_LIST_HEAD (&fw->sections);
drivers/gpu/drm/panthor/panthor_fw_regs.h +0 -2
@@ -4,8 +4,6 @@#ifndef __PANTHOR_FW_REGS_H__#define __PANTHOR_FW_REGS_H__ -#define MCU_CONTROL_BASE 0x700 -#define MCU_CONTROL 0x0#define MCU_CONTROL_ENABLE 1#define MCU_CONTROL_AUTO 2
drivers/gpu/drm/panthor/panthor_gpu.c +2 -2
@@ -159,7 +159,7 @@ int panthor_gpu_init(struct panthor_device *ptdev)if (!gpu)return -ENOMEM ; - gpu->iomem = ptdev->iomem +GPU_CONTROL_BASE ; + gpu->iomem = ptdev->iomem + ptdev->hw->regs.gpu_control.offset;spin_lock_init (&gpu->reqs_lock);init_waitqueue_head (&gpu->reqs_acked);mutex_init (&gpu->cache_flush_lock);
@@ -176,7 +176,7 @@ int panthor_gpu_init(struct panthor_device *ptdev)return irq; ret =panthor_irq_request (ptdev, &ptdev->gpu->irq, irq, - ptdev->iomem +GPU_INT_BASE ,"gpu" , + gpu->iomem +GPU_INT_BASE ,"gpu" , panthor_gpu_irq_threaded_handler);if (ret)return ret;
drivers/gpu/drm/panthor/panthor_gpu_regs.h +0 -2
@@ -4,8 +4,6 @@#ifndef __PANTHOR_GPU_REGS_H__#define __PANTHOR_GPU_REGS_H__ -#define GPU_CONTROL_BASE 0x0 -#define GPU_ID 0x0#define GPU_ARCH_MAJOR (x) ((x) >> 28)#define GPU_ARCH_MINOR (x) (((x) & GENMASK(27, 24)) >> 24)
drivers/gpu/drm/panthor/panthor_hw.c +21 -2
@@ -38,6 +38,14 @@ static struct panthor_hw panthor_hw_arch_v10 = { .power_changed_off = panthor_gpu_power_changed_off, .power_changed_on = panthor_gpu_power_changed_on, }, + .regs = { + .gpu_control = { + .offset = 0x0, + }, + .mcu_control = { + .offset = 0x700, + }, + }, }; static struct panthor_hw panthor_hw_arch_v14 = {
@@ -46,6 +54,17 @@ static struct panthor_hw panthor_hw_arch_v14 = { .l2_power_off = panthor_pwr_l2_power_off, .l2_power_on = panthor_pwr_l2_power_on, }, + .regs = { + .gpu_control = { + .offset = 0x0, + }, + .mcu_control = { + .offset = 0x700, + }, + .pwr_control = { + .offset = 0x800, + }, + }, };static struct panthor_hw_entry panthor_hw_match[] = {
@@ -197,7 +216,7 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) {unsigned int i; -void __iomem *gpu_iomem = ptdev->iomem +GPU_CONTROL_BASE ; +void __iomem *gpu_iomem = ptdev->iomem + ptdev->hw->regs.gpu_control.offset; ptdev->gpu_info.csf_id =gpu_read (gpu_iomem,GPU_CSF_ID ); ptdev->gpu_info.gpu_rev =gpu_read (gpu_iomem,GPU_REVID );
@@ -223,7 +242,7 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev) ptdev->gpu_info.gpu_features =gpu_read64 (gpu_iomem,GPU_FEATURES );if (panthor_hw_has_pwr_ctrl (ptdev)) { -void __iomem *pwr_iomem = gpu_iomem +PWR_CONTROL_BASE ; +void __iomem *pwr_iomem = ptdev->iomem + ptdev->hw->regs.pwr_control.offset;/* Introduced in arch 14.x */ ptdev->gpu_info.l2_present =gpu_read64 (pwr_iomem,PWR_L2_PRESENT );
drivers/gpu/drm/panthor/panthor_hw.h +27 -2
@@ -27,14 +27,39 @@ struct panthor_hw_ops {void (*power_changed_off)(struct panthor_device *ptdev); }; +/** struct panthor_hw_regbank - Register offset and instance stride information */ +struct panthor_hw_regbank { +/** @offset: Register offset relative to &struct panthor_device.iomem */ +u32 offset; + +/** +* @stride: Register offset between instances, or 0 for non-instanced +* registers +*/ +u32 stride; +}; + +/** struct panthor_hw_regs_layout - Hardware register bank layout */ +struct panthor_hw_regs_layout { +/** @gpu_control: GPU_CONTROL register bank layout */ +struct panthor_hw_regbank gpu_control; + +/** @pwr_control: PWR_CONTROL register bank layout */ +struct panthor_hw_regbank pwr_control; + +/** @mcu_control: MCU_CONTROL register bank layout */ +struct panthor_hw_regbank mcu_control; +}; +/** * struct panthor_hw - GPU specific register mapping and functions */ struct panthor_hw { -/** @features: Bitmap containing panthor_hw_feature */ -/** @ops: Panthor HW specific operations */ struct panthor_hw_ops ops; + +/** @regs: Hardware register bank layout */ +struct panthor_hw_regs_layout regs; };int panthor_hw_init (struct panthor_device *ptdev);
drivers/gpu/drm/panthor/panthor_pwr.c +1 -1
@@ -502,7 +502,7 @@ int panthor_pwr_init(struct panthor_device *ptdev)if (!pwr)return -ENOMEM ; - pwr->iomem = ptdev->iomem +PWR_CONTROL_BASE ; + pwr->iomem = ptdev->iomem + ptdev->hw->regs.pwr_control.offset;spin_lock_init (&pwr->reqs_lock);init_waitqueue_head (&pwr->reqs_acked); ptdev->pwr = pwr;
drivers/gpu/drm/panthor/panthor_pwr_regs.h +0 -2
@@ -4,8 +4,6 @@#ifndef __PANTHOR_PWR_REGS_H__#define __PANTHOR_PWR_REGS_H__ -#define PWR_CONTROL_BASE 0x800 -#define PWR_INT_BASE 0x0#define PWR_IRQ_POWER_CHANGED_SINGLE BIT(0)#define PWR_IRQ_POWER_CHANGED_ALL BIT(1)
Signature · 1 line
2.43.0
PATCH v2 7/28 drm/panthor: Derive MMU AS register addresses from base and stride
In reply to Karunika ChooMove the MMU address-space register layout into the hardware description by storing the MMU_AS base offset and per-AS stride in the Panthor HW map.
Use those values to compute the iomem pointer for each AS slot and make the MMU AS register definitions relative to the per-slot register window instead of hard-coding the slot offset in every register macro.
This prepares the MMU code for GPUs where the MMU AS register region is not at a fixed offset while keeping the existing register accesses scoped to a single AS window.
---
v2:
- Picked up R-b from Liviu
- Avoid enabling all AS IRQs on init and replace with explicit IRQ clear to preserve init behaviour. AS IRQs are enabled as part of panthor_mmu_as_enable(). This also prevents accessing NULL iomem pointers for initialized AS during init per sashiko's comment.
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- align with updated panthor_hw_regbank structure.
- moved AS iomem tracking into panthor_as_slot and introduced as_iomem() to retrieve it.
drivers/gpu/drm/panthor/panthor_hw.c | 8 ++++ drivers/gpu/drm/panthor/panthor_hw.h | 3 ++ drivers/gpu/drm/panthor/panthor_mmu.c | 47 ++++++++++++++-------- drivers/gpu/drm/panthor/panthor_mmu_regs.h | 23 +++++------ 4 files changed, 51 insertions(+), 30 deletions(-)
drivers/gpu/drm/panthor/panthor_hw.c +8 -0
@@ -45,6 +45,10 @@ static struct panthor_hw panthor_hw_arch_v10 = { .mcu_control = { .offset = 0x700, }, + .mmu_as_control = { + .offset = 0x2400, + .stride = 0x40, + }, }, };
@@ -64,6 +68,10 @@ static struct panthor_hw panthor_hw_arch_v14 = { .pwr_control = { .offset = 0x800, }, + .mmu_as_control = { + .offset = 0x2400, + .stride = 0x40, + }, }, };
drivers/gpu/drm/panthor/panthor_hw.h +3 -0
@@ -49,6 +49,9 @@ struct panthor_hw_regs_layout {/** @mcu_control: MCU_CONTROL register bank layout */ struct panthor_hw_regbank mcu_control; + +/** @mmu_as_control: MMU_AS_CONTROL register bank layout */ +struct panthor_hw_regbank mmu_as_control; };/**
drivers/gpu/drm/panthor/panthor_mmu.c +31 -16
127 lines not on this page · raw message
drivers/gpu/drm/panthor/panthor_mmu_regs.h +9 -14
@@ -11,13 +11,8 @@/* AS_COMMAND register commands */ -#define MMU_AS_BASE 0x2400 - -#define MMU_AS_SHIFT 6 -#define MMU_AS (as) ((as) << MMU_AS_SHIFT) - -#define AS_TRANSTAB (as) (MMU_AS(as) + 0x0) -#define AS_MEMATTR (as) (MMU_AS(as) + 0x8) +#define AS_TRANSTAB 0x0 +#define AS_MEMATTR 0x8#define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2)#define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL (w, r) ((3 << 2) | \ ((w) ? BIT(0) : 0) | \
@@ -29,8 +24,8 @@#define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6)#define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6)#define AS_MEMATTR_AARCH64_FAULT (3 << 6) -#define AS_LOCKADDR (as) (MMU_AS(as) + 0x10) -#define AS_COMMAND (as) (MMU_AS(as) + 0x18) +#define AS_LOCKADDR 0x10 +#define AS_COMMAND 0x18#define AS_COMMAND_NOP 0#define AS_COMMAND_UPDATE 1#define AS_COMMAND_LOCK 2
@@ -38,16 +33,16 @@#define AS_COMMAND_FLUSH_PT 4#define AS_COMMAND_FLUSH_MEM 5#define AS_LOCK_REGION_MIN_SIZE (1ULL << 15) -#define AS_FAULTSTATUS (as) (MMU_AS(as) + 0x1C) +#define AS_FAULTSTATUS 0x1C#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8)#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8)#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8)#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8)#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) -#define AS_FAULTADDRESS (as) (MMU_AS(as) + 0x20) -#define AS_STATUS (as) (MMU_AS(as) + 0x28) +#define AS_FAULTADDRESS 0x20 +#define AS_STATUS 0x28#define AS_STATUS_AS_ACTIVE BIT(0) -#define AS_TRANSCFG (as) (MMU_AS(as) + 0x30) +#define AS_TRANSCFG 0x30#define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0)#define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0)#define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0)
@@ -65,6 +60,6 @@#define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34)#define AS_TRANSCFG_WXN BIT(35)#define AS_TRANSCFG_XREADABLE BIT(36) -#define AS_FAULTEXTRA (as) (MMU_AS(as) + 0x38) +#define AS_FAULTEXTRA 0x38#endif /* __PANTHOR_MMU_REGS_H__ */
Signature · 1 line
2.43.0
PATCH v2 8/28 dt-bindings: gpu: mali-gen5-am: Add Mali 5th-Gen AM schema
In reply to Karunika ChooAdd a separate device-tree schema for Mali 5th-Gen AM GPUs.
AM_GOVERNOR controls GPU frequency. The GPU node does not accept OPP, cooling or GPU supply properties.
---
v2:
- Move arm,mali-gen5-am support from arm,mali-valhall-csf.yaml to a separate arm,mali-gen5-am.yaml schema.
- Move the AM GPU example to the new schema and add the interrupt binding headers.
- Add the new schema to the Panthor MAINTAINERS entry.
.../bindings/gpu/arm,mali-gen5-am.yaml | 90 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +90 -0
@@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th Gen AM GPU + +maintainers: + - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + $nodename: + pattern: '^gpu@[a-f0-9]+$' + + compatible: + const: arm,mali-gen5-am + + reg: + maxItems: 1 + + interrupts: + items: + - description: Job interrupt + - description: MMU interrupt + - description: GPU interrupt + + interrupt-names: + items: + - const: job + - const: mmu + - const: gpu + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + items: + - const: core + - enum: + - coregroup + - stacks + - const: stacks + + nvmem-cells: + items: + - description: bitmask of functional shader cores + + nvmem-cell-names: + items: + - const: shader-present + + power-domains: + minItems: 1 + maxItems: 5 + + power-domain-names: + minItems: 1 + maxItems: 5 + + dma-coherent: true + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu@100000 { + compatible = "arm,mali-gen5-am"; + reg = <0x100000 0x480000>; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "job", "mmu", "gpu"; + clocks = <&gpu_clock 0>, <&gpu_clock 1>, <&gpu_clock 2>; + clock-names = "core", "coregroup", "stacks"; + }; +...
MAINTAINERS +1 -0
@@ -2400,6 +2400,7 @@ M: Liviu Dudau <[email protected]> L: [email protected] S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/devicetree/bindings/gpu/arm,mali-gen5-am*.yaml F: Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml F: drivers/gpu/drm/ci/xfails/panthor* F: drivers/gpu/drm/panthor/
Signature · 1 line
2.43.0
Re: [PATCH v2 08/28] dt-bindings: gpu: mali-gen5-am: Add Mali 5th-Gen AM schema
Quoted 30 lines · Karunika Choo
Add a separate device-tree schema for Mali 5th-Gen AM GPUs.
AM_GOVERNORcontrols GPU frequency. The GPU node does not accept OPP, cooling or GPU supply properties.Signed-off-by Karunika Choo <[email protected]>---
v2:
- Move arm,mali-gen5-am support from arm,mali-valhall-csf.yaml to a separate arm,mali-gen5-am.yaml schema.
- Move the AM GPU example to the new schema and add the interrupt binding headers.
- Add the new schema to the PanthorMAINTAINERSentry..../bindings/gpu/arm,mali-gen5-am.yaml | 90 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yamlDocumentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +5
-0@@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 15
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +10
-0+ +title: ARM Mali 5th Gen AM GPU + +maintainers: + - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + $nodename: + pattern: '^gpu@[a-f0-9]+$'
Same comments as last time.
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 18
Quoted 3 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +3
-0+ + compatible: + const: arm,mali-gen5-am
Same comments as last time. Seems like you just ignore review, so I will finish here.
Respond to review. Dropping from DT patchwork.
Best regards,
Krzysztof
Re: [PATCH v2 08/28] dt-bindings: gpu: mali-gen5-am: Add Mali 5th-Gen AM schema
Quoted 35 lines · Krzysztof Kozlowski
Quoted 34 lines · Karunika Choo
Add a separate device-tree schema for Mali 5th-Gen AM GPUs.
AM_GOVERNORcontrols GPU frequency. The GPU node does not accept OPP, cooling or GPU supply properties.Signed-off-by Karunika Choo <[email protected]>---
v2:
- Move arm,mali-gen5-am support from arm,mali-valhall-csf.yaml to a separate arm,mali-gen5-am.yaml schema.
- Move the AM GPU example to the new schema and add the interrupt binding headers.
- Add the new schema to the PanthorMAINTAINERSentry..../bindings/gpu/arm,mali-gen5-am.yaml | 90 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yamlDocumentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +9
-0@@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th Gen AM GPU + +maintainers:
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 15
Quoted 6 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +6
-0+ - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + $nodename: + pattern: '^gpu@[a-f0-9]+$'Same comments as last time.
Sorry, do you mean that 'gpu' not generic enough?
Quoted 7 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 18
Quoted 3 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +3
-0+ + compatible: + const: arm,mali-gen5-amSame comments as last time. Seems like you just ignore review, so I will finish here.
Hi, we are trying to provide initial support for v15. The vendor identifiers will be added once there is an available device.
Quoted 5 lines
Respond to review. Dropping from DT patchwork.
Best regards,
Krzysztof
Re: [PATCH v2 08/28] dt-bindings: gpu: mali-gen5-am: Add Mali 5th-Gen AM schema
Quoted 45 lines · Karunika Choo
Quoted 35 lines · Krzysztof Kozlowski
Quoted 34 lines · Karunika Choo
Add a separate device-tree schema for Mali 5th-Gen AM GPUs.
AM_GOVERNORcontrols GPU frequency. The GPU node does not accept OPP, cooling or GPU supply properties.Signed-off-by Karunika Choo <[email protected]>---
v2:
- Move arm,mali-gen5-am support from arm,mali-valhall-csf.yaml to a separate arm,mali-gen5-am.yaml schema.
- Move the AM GPU example to the new schema and add the interrupt binding headers.
- Add the new schema to the PanthorMAINTAINERSentry..../bindings/gpu/arm,mali-gen5-am.yaml | 90 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yamlDocumentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +9
-0@@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th Gen AM GPU + +maintainers:Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 15
Quoted 6 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +6
-0+ - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + $nodename: + pattern: '^gpu@[a-f0-9]+$'Same comments as last time.
Quoted 1 line
Sorry, do you mean that 'gpu' not generic enough?
I asked to drop the node name completely.
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +3
-0+ + compatible: + const: arm,mali-gen5-am
Quoted 7 lines
Quoted 3 lines
Same comments as last time. Seems like you just ignore review, so I will finish here.
Hi, we are trying to provide initial support for v15. The vendor identifiers will be added once there is an available device.
So how can this initial support be run? Which board has it? I received only three patches of entire thread, but if there was DTS I would be cc-ed. I can't find such patch.
Best regards,
Krzysztof
Re: [PATCH v2 08/28] dt-bindings: gpu: mali-gen5-am: Add Mali 5th-Gen AM schema
Quoted 46 lines · Krzysztof Kozlowski
Quoted 45 lines · Karunika Choo
Quoted 43 lines · Krzysztof Kozlowski
Quoted 30 lines · Karunika Choo
Add a separate device-tree schema for Mali 5th-Gen AM GPUs.
AM_GOVERNORcontrols GPU frequency. The GPU node does not accept OPP, cooling or GPU supply properties.Signed-off-by Karunika Choo <[email protected]>---
v2:
- Move arm,mali-gen5-am support from arm,mali-valhall-csf.yaml to a separate arm,mali-gen5-am.yaml schema.
- Move the AM GPU example to the new schema and add the interrupt binding headers.
- Add the new schema to the PanthorMAINTAINERSentry..../bindings/gpu/arm,mali-gen5-am.yaml | 90 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yamlDocumentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +5
-0@@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml#Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 15
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +10
-0+ +title: ARM Mali 5th Gen AM GPU + +maintainers: + - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + $nodename: + pattern: '^gpu@[a-f0-9]+$'Same comments as last time.
Quoted 4 lines
Quoted 1 line
Sorry, do you mean that 'gpu' not generic enough?
I asked to drop the node name completely.
ah! Understood. Will do that in v3.
Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml line 18
Quoted 4 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am.yaml new file +3
-0+ + compatible: + const: arm,mali-gen5-amSame comments as last time. Seems like you just ignore review, so I will finish here.
Quoted 7 lines
Quoted 3 lines
Hi, we are trying to provide initial support for v15. The vendor identifiers will be added once there is an available device.
So how can this initial support be run? Which board has it? I received only three patches of entire thread, but if there was DTS I would be cc-ed. I can't find such patch.
Apologies for the trouble. This was tested on internal FPGAs, but let me try to see if I can add a representative DTS for one of our publicly available FVP platforms in v3.
Quoted 3 lines
Best regards,
Krzysztof
PATCH v2 9/28 drm/panthor: Add Mali v15 hardware support
In reply to Karunika ChooAdd the panthor hardware description for Mali v15 GPUs and hook it into device matching.
This includes the v15 register map and product identification needed to populate the GPU information exposed by the driver and its uAPI.
Add compatibility string for v15 GPUs and bump drm minor to 10.
---
v2:
- check as_count is non-zero before generating as_present mask per sashiko's comment.
- Link: https://lore.kernel.org/all/[email protected]/
- clean up l2_features value assignment.
- removed duplicated GPU_FEATURES macro definitions
- Picked up R-b from Liviu
v1:
- make COHERENCY_FEATURES register read use cached gpu_info values.
- Added Mali-G2 name variants and NX aware model identification.
- fix premature reading of l2_features gpu_info field during panthor_hw_info_init().
- build as_present using GENMASK.
drivers/gpu/drm/panthor/panthor_drv.c | 5 +- drivers/gpu/drm/panthor/panthor_fw.c | 1 + drivers/gpu/drm/panthor/panthor_gpu.c | 3 +- .../drm/panthor/panthor_gpu_discover_regs.h | 23 +++++ drivers/gpu/drm/panthor/panthor_heap.c | 3 +- drivers/gpu/drm/panthor/panthor_hw.c | 96 ++++++++++++++++++- drivers/gpu/drm/panthor/panthor_hw.h | 13 +++ include/uapi/drm/panthor_drm.h | 10 +- 8 files changed, 145 insertions(+), 9 deletions(-)
drivers/gpu/drm/panthor/panthor_drv.c +4 -1
@@ -1785,6 +1785,8 @@ static void panthor_debugfs_init(struct drm_minor *minor)* - 1.8 - extends DEV_QUERY_TIMESTAMP_INFO with flags * - 1.9 - adds DRM_PANTHOR_DEV_QUERY_MMU_INFO query * - adds DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE flag +* - 1.10 - adds thread_num_active_granularity, gpu_rev_wide, l2_features_wide, +* and gpu_id_wide to drm_panthor_gpu_info */ static const struct drm_driver panthor_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ |
@@ -1798,7 +1800,7 @@ static const struct drm_driver panthor_drm_driver = { .name = "panthor", .desc = "Panthor DRM driver", .major = 1, - .minor = 9, + .minor = 10, .gem_prime_import_sg_table = panthor_gem_prime_import_sg_table, .gem_prime_import = panthor_gem_prime_import,
@@ -1881,6 +1883,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "mediatek,mt8196-mali", .data = &soc_data_mediatek_mt8196, }, { .compatible = "rockchip,rk3588-mali" }, { .compatible = "arm,mali-valhall-csf" }, + { .compatible = "arm,mali-gen5-am" }, {} };MODULE_DEVICE_TABLE (of, dt_match);
drivers/gpu/drm/panthor/panthor_fw.c +1 -0
@@ -1563,3 +1563,4 @@ MODULE_FIRMWARE("arm/mali/arch11.8/mali_csffw.bin");MODULE_FIRMWARE ("arm/mali/arch12.8/mali_csffw.bin" );MODULE_FIRMWARE ("arm/mali/arch13.8/mali_csffw.bin" );MODULE_FIRMWARE ("arm/mali/arch14.8/mali_csffw.bin" ); +MODULE_FIRMWARE ("arm/mali/arch15.8/mali_csffw.bin" );
drivers/gpu/drm/panthor/panthor_gpu.c +1 -2
@@ -503,8 +503,7 @@ int panthor_gpu_coherency_init(struct panthor_device *ptdev)/* Check if the ACE-Lite coherency protocol is actually supported by the GPU. * ACE protocol has never been supported for command stream frontend GPUs. */ -if ((gpu_read (ptdev->gpu->iomem,GPU_COHERENCY_FEATURES ) & -GPU_COHERENCY_PROT_BIT (ACE_LITE ))) { +if ((ptdev->gpu_info.coherency_features &GPU_COHERENCY_PROT_BIT (ACE_LITE ))) { ptdev->gpu_info.selected_coherency =GPU_COHERENCY_ACE_LITE ;return 0 ; }
drivers/gpu/drm/panthor/panthor_gpu_discover_regs.h +23 -0
@@ -16,4 +16,27 @@#define GPU_WIDE_VER_MINOR (x) (((x) & GENMASK_U64(15, 8)) >> 8)#define GPU_WIDE_VER_STATUS (x) ((x) & GENMASK_U64(7, 0)) +#define DISCOVER_REVIDR 0x8 +#define DISCOVER_GPU_FEATURES 0x20 +#define GPU_FEATURES_VARIABLE_RATE_SHADING BIT(0) +#define GPU_FEATURES_SIMD_STATE BIT(1) +#define GPU_FEATURES_CROSS_STREAM_SYNC BIT(3) +#define GPU_FEATURES_LD_LEA_TENSOR_INSTRUCTIONS BIT(6) +#define DISCOVER_MCU_FEATURES 0x40 +#define DISCOVER_PRFCNT_FEATURES 0x50 +#define PRFCNT_FEATURES_COUNTER_BLOCK_SIZE (x) (((x) & GENMASK(7, 0)) << 8) +#define DISCOVER_DOORBELL_FEATURES 0x60 +#define DISCOVER_MEM_FEATURES 0x100 +#define DISCOVER_MMU_FEATURES 0x108 +#define MMU_FEATURES_AS_COUNT (x) (((x) & GENMASK(23, 16)) >> 16) +#define DISCOVER_AMBA_FEATURES 0x120 + +#define DISCOVER_L2_FEATURES 0x128 +#define DISCOVER_TILER_FEATURES 0x200 +#define DISCOVER_CORE_FEATURES 0x300 +#define DISCOVER_THREAD_FEATURES 0x320 +#define DISCOVER_THREAD_MAX_THREADS 0x330 +#define DISCOVER_THREAD_NUM_ACTIVE_GRANULARITY 0x334 +#define DISCOVER_TEXTURE_FEATURES 0x360 +#endif /* __PANTHOR_GPU_DISCOVER_REGS_H__ */
drivers/gpu/drm/panthor/panthor_heap.c +2 -1
@@ -11,6 +11,7 @@#include "panthor_gem.h" #include "panthor_gpu_regs.h" #include "panthor_heap.h" +#include "panthor_hw.h" #include "panthor_mmu.h" /*
@@ -105,7 +106,7 @@ struct panthor_heap_pool {static int panthor_heap_ctx_stride (struct panthor_device *ptdev) { -u32 l2_features = ptdev->gpu_info.l2_features; +u64 l2_features =panthor_hw_get_l2_features (ptdev);u32 gpu_cache_line_size =GPU_L2_FEATURES_LINE_SIZE (l2_features);return ALIGN (HEAP_CONTEXT_SIZE , gpu_cache_line_size);
drivers/gpu/drm/panthor/panthor_hw.c +93 -3
157 lines not on this page · raw message
drivers/gpu/drm/panthor/panthor_hw.h +13 -0
@@ -95,4 +95,17 @@ static inline bool panthor_hw_has_neural(struct panthor_device *ptdev) ptdev->gpu_info.gpu_features & GPU_FEATURES_NX); } +static inline bool panthor_hw_has_gpu_discover (struct panthor_device *ptdev) +{ +return ptdev->gpu_id.arch_major >=15 ; +} + +static inline u64 panthor_hw_get_l2_features (struct panthor_device *ptdev) +{ +if (panthor_hw_has_gpu_discover (ptdev)) +return ptdev->gpu_info.l2_features_wide; + +return ptdev->gpu_info.l2_features; +} +#endif /* __PANTHOR_HW_H__ */
include/uapi/drm/panthor_drm.h +8 -2
@@ -371,8 +371,8 @@ struct drm_panthor_gpu_info {/** @core_features: Used to discriminate core variants when they exist. */ __u32 core_features; -/** @pad: MBZ. */ -__u32 pad; +/** @thread_num_active_granularity: Granularity of number of active threads */ +__u32 thread_num_active_granularity;/** @gpu_features: Bitmask describing supported GPU-wide features */ __u64 gpu_features;
@@ -389,6 +389,12 @@ struct drm_panthor_gpu_info {#define DRM_PANTHOR_WIDE_VERSION_MAJOR (x) (((x) >> 16) & 0xff)#define DRM_PANTHOR_WIDE_VERSION_MINOR (x) (((x) >> 8) & 0xff)#define DRM_PANTHOR_WIDE_VERSION_STATUS (x) ((x) & 0xff) + +/** @gpu_rev_wide: 64-bit GPU revision for v15 onwards */ +__u64 gpu_rev_wide; + +/** @l2_features_wide: 64-bit L2_FEATURES for v15 onwards */ +__u64 l2_features_wide; };/**
Signature · 1 line
2.43.0
PATCH v2 10/28 drm/panthor: Skip devfreq when no OPP table is present
In reply to Karunika ChooOn Mali v15 AM systems, frequency scaling is handled outside panthor by the AM_GOVERNOR block, so the GPU DT node may not provide an OPP table.
Make panthor_devfreq_init() return early when dev_pm_opp_get_opp_table() returns -ENODEV, and guard the devfreq helper paths against a missing devfreq instance. Also make it so that frequency can be queried even if the devfreq instance is missing.
This keeps devfreq enabled for existing platforms while allowing v15 AM systems to probe without a local devfreq setup.
---
v2:
- Directly call functions instead of storing function pointers.
- Picked up R-b from Liviu
v1:
- Only skip panthor_devfreq init when OPP lookup returns -ENODEV instead of direct DT-property check.
- Support frequency query without devfreq.
drivers/gpu/drm/panthor/panthor_devfreq.c | 29 +++++++++++++++++------ drivers/gpu/drm/panthor/panthor_hw.h | 6 +++++ 2 files changed, 28 insertions(+), 7 deletions(-)
drivers/gpu/drm/panthor/panthor_devfreq.c +22 -7
@@ -12,6 +12,7 @@#include "panthor_devfreq.h" #include "panthor_device.h" +#include "panthor_hw.h" /** * struct panthor_devfreq - Device frequency management
@@ -164,6 +165,19 @@ int panthor_devfreq_init(struct panthor_device *ptdev)*/ table =dev_pm_opp_get_opp_table (dev);if (IS_ERR_OR_NULL (table)) { +/* +* On v15 GPUs, frequency scaling is handled outside of panthor +* by the AM_GOVERNOR block, so the GPU DT node may not provide +* an OPP table. In such cases, do not initialize devfreq for +* panthor. +*/ +if (panthor_hw_is_gen5_am (ptdev->base.dev) && +PTR_ERR (table) == -ENODEV ) { +drmm_kfree (&ptdev->base, pdevfreq); + ptdev->devfreq =NULL ; +return 0 ; + } + ret =devm_pm_opp_set_regulators (dev, reg_names);if (ret && ret != -ENODEV ) {if (ret != -EPROBE_DEFER )
@@ -267,7 +281,7 @@ void panthor_devfreq_resume(struct panthor_device *ptdev) {struct panthor_devfreq *pdevfreq = ptdev->devfreq; -if (!pdevfreq->devfreq) +if (!pdevfreq || !pdevfreq->devfreq)return ;panthor_devfreq_reset (pdevfreq);
@@ -279,7 +293,7 @@ void panthor_devfreq_suspend(struct panthor_device *ptdev) {struct panthor_devfreq *pdevfreq = ptdev->devfreq; -if (!pdevfreq->devfreq) +if (!pdevfreq || !pdevfreq->devfreq)return ;drm_WARN_ON (&ptdev->base,devfreq_suspend_device (pdevfreq->devfreq));
@@ -290,7 +304,7 @@ void panthor_devfreq_record_busy(struct panthor_device *ptdev)struct panthor_devfreq *pdevfreq = ptdev->devfreq;unsigned long irqflags; -if (!pdevfreq->devfreq) +if (!pdevfreq || !pdevfreq->devfreq)return ;spin_lock_irqsave (&pdevfreq->lock, irqflags);
@@ -306,7 +320,7 @@ void panthor_devfreq_record_idle(struct panthor_device *ptdev)struct panthor_devfreq *pdevfreq = ptdev->devfreq;unsigned long irqflags; -if (!pdevfreq->devfreq) +if (!pdevfreq || !pdevfreq->devfreq)return ;spin_lock_irqsave (&pdevfreq->lock, irqflags);
@@ -323,10 +337,11 @@ unsigned long panthor_devfreq_get_freq(struct panthor_device *ptdev)unsigned long freq =0 ;int ret; -if (!pdevfreq->devfreq) -return 0 ; +if (!pdevfreq || !pdevfreq->devfreq) + ret =panthor_devfreq_get_cur_freq (ptdev->base.dev, &freq); +else + ret = pdevfreq->devfreq->profile->get_cur_freq (ptdev->base.dev, &freq); - ret = pdevfreq->devfreq->profile->get_cur_freq (ptdev->base.dev, &freq);if (ret)return 0 ;
drivers/gpu/drm/panthor/panthor_hw.h +6 -0
@@ -108,4 +108,10 @@ static inline u64 panthor_hw_get_l2_features(struct panthor_device *ptdev) return ptdev->gpu_info.l2_features; } +static inline bool panthor_hw_is_gen5_am (struct device *dev) +{ +return device_property_match_string (dev,"compatible" , +"arm,mali-gen5-am" ) >=0 ; +} +#endif /* __PANTHOR_HW_H__ */
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 10/28] drm/panthor: Skip devfreq when no OPP table is present
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Medium] drm/panthor: panthor_devfreq_init() leaves fast_rate at 0 on early return --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Medium] drm/panthor: panthor_devfreq_init() leaves fast_rate at 0 on early return
--
commit f3bfa3d1d539b4b1bfaa2d96f490e98746dad160
Author: Karunika Choo <[email protected]>
drm/panthor: Skip devfreq when no OPP table is present
This commit skips devfreq initialization on Mali v15 AM systems when no OPP table is present, guards the devfreq helpers against a NULL devfreq instance, and falls back to clk_get_rate() when querying the current frequency without devfreq.
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_devfreq.c +0
-0
[ ... ]
Quoted 6 lines
drivers/gpu/drm/panthor/panthor_devfreq.c +2
-0@@ -164,6 +165,19 @@ int panthor_devfreq_init(struct panthor_device *ptdev)*/ table =dev_pm_opp_get_opp_table (dev);if (IS_ERR_OR_NULL (table)) { +/* +* On v15 GPUs, frequency scaling is handled outside of panthor
drivers/gpu/drm/panthor/panthor_devfreq.c int panthor_devfreq_init(struct panthor_device *ptdev) · line 179
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_devfreq.c +10
-0+* by the AM_GOVERNOR block, so the GPU DT node may not provide +* an OPP table. In such cases, do not initialize devfreq for +* panthor. +*/ +if (panthor_hw_is_gen5_am (ptdev->base.dev) && +PTR_ERR (table) == -ENODEV ) { +drmm_kfree (&ptdev->base, pdevfreq); + ptdev->devfreq =NULL ; +return 0 ; + }
[Severity: Medium]
As reported by Steven Price on RFC [1], does returning early here leave ptdev->fast_rate at 0? ptdev->fast_rate is only populated later in panthor_devfreq_init() via dev_pm_opp_find_freq_floor(), and panthor_gpu_show_fdinfo() unconditionally prints it:
drivers/gpu/drm/panthor/panthor_drv.c:panthor_gpu_show_fdinfo() {
...
drm_printf(p, "drm-maxfreq-panthor:\t%lu Hz\n", ptdev->fast_rate);
drm_printf(p, "drm-curfreq-panthor:\t%lu Hz\n",
panthor_devfreq_get_freq(ptdev));
}On v15 AM systems without an OPP table, reading fdinfo will report "drm-maxfreq-panthor: 0 Hz" alongside a non-zero current frequency, breaking userspace GPU utilization calculations that divide cycle counts by drm-maxfreq-panthor.
[1] https://lore.kernel.org/r/[email protected]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
PATCH v2 11/28 dt-bindings: gpu: panthor: Document AM system bindings
In reply to Karunika ChooMali 5th-Gen AM GPUs expose an AM_SYSTEM block for GPU-wide control and the AM_ASSIGN block for HW resource assignment outside the GPU job submission register window.
Document the system node compatible, register and interrupt resources, GPU clock, and assignment properties for HW resource assignment.
---
v2:
- Add an optional AM_ASSIGN register range. Require this range when the assignments node is present.
- Describe resource-group assignments for AXI buses, partitions, slices and access windows on partition-capable GPUs.
- Allow gpu-arbitration child nodes and the #address-cells, #size-cells and ranges properties.
- Remove the panthor-system node-name restriction.
- Remove gpu-supply from the schema and example.
- Add an example with assignments for partition-capable GPU with four resource groups.
- Move the MAINTAINERS update to the GPU schema patch.
.../bindings/gpu/arm,mali-gen5-am-system.yaml | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +196 -0
@@ -0,0 +1,196 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright 2026 ARM Limited. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am-system.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th-Gen GPU System Device + +maintainers: + - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + compatible: + items: + - const: arm,mali-gen5-am-system + + reg: + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 1 + items: + - const: system + - const: assign + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + dma-coherent: true + + "#address-cells": true + + "#size-cells": true + + ranges: true + + assignments: + type: object + additionalProperties: false + description: + Resource group HW resource assignment. Only valid for partition-capable + GPUs. + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + required: + - "#address-cells" + - "#size-cells" + + patternProperties: + "^resource-group@[0-3]$": + type: object + additionalProperties: false + + properties: + reg: + items: + - maximum: 3 + description: Resource group number. + + arm,axi-bus: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 1 + default: 0 + description: + Static resource-group to AXI bus assignment. Valid field values + are 0 for AXI_A and 1 for AXI_B. + + arm,partition-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xf + default: 0 + description: + Static partition-control to resource-group assignment. Bit N + selects partition control ID N. Mask must be disjoint across + resource groups. Unassigned partitions will be assigned to + resource group 0 by default. + + arm,slice-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xff + default: 0 + description: + Static slice to resource-group assignment. Bit N selects slice ID + N. Mask must be disjoint across resource groups. Unassigned slices + will be assigned to resource group 0 by default. + + arm,access-window-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xffff + default: 0 + description: + Static access-window to resource-group assignment. Bit N selects + access window ID N. Masks must be disjoint across resource groups. + Unassigned access-windows will be assigned to resource group 0 by + default. + + required: + - reg + +patternProperties: + '^gpu-arbitration@[a-f0-9]+$': + $ref: arm,mali-gen5-am-arbitration.yaml# + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + +additionalProperties: false + +allOf: + - if: + required: + - assignments + then: + properties: + reg: + minItems: 2 + reg-names: + minItems: 2 + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-system@68000000 { + compatible = "arm,mali-gen5-am-system"; + reg = <0x68000000 0x10000>; + reg-names = "system"; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mali_gpu_clk>; + }; + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-system@68000000 { + compatible = "arm,mali-gen5-am-system"; + reg = <0x68000000 0x10000>, <0x68010000 0x10000>; + reg-names = "system", "assign"; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mali_gpu_clk>; + + assignments { + #address-cells = <1>; + #size-cells = <0>; + + resource-group@0 { + reg = <0>; + arm,axi-bus = <0>; + arm,partition-mask = <0x1>; + arm,slice-mask = <0x3>; + arm,access-window-mask = <0xf>; + }; + + resource-group@1 { + reg = <1>; + arm,axi-bus = <0>; + arm,partition-mask = <0x2>; + arm,slice-mask = <0xc>; + arm,access-window-mask = <0xf0>; + }; + + resource-group@2 { + reg = <2>; + arm,axi-bus = <1>; + arm,partition-mask = <0x4>; + arm,slice-mask = <0x30>; + arm,access-window-mask = <0xf00>; + }; + + resource-group@3 { + reg = <3>; + arm,axi-bus = <1>; + arm,partition-mask = <0x8>; + arm,slice-mask = <0xc0>; + arm,access-window-mask = <0xf000>; + }; + }; + }; + +...
Signature · 1 line
2.43.0
Re: [PATCH v2 11/28] dt-bindings: gpu: panthor: Document AM system bindings
Quoted 43 lines · Karunika Choo
Mali 5th-Gen AM GPUs expose an
AM_SYSTEMblock for GPU-wide control and theAM_ASSIGNblock for HW resource assignment outside the GPU job submission register window.Document the system node compatible, register and interrupt resources, GPU clock, and assignment properties for HW resource assignment.
Signed-off-by Karunika Choo <[email protected]>---
v2:
- Add an optionalAM_ASSIGNregister range. Require this range when the assignments node is present.
- Describe resource-group assignments for AXI buses, partitions, slices and access windows on partition-capable GPUs.
- Allow gpu-arbitration child nodes and the #address-cells, #size-cells and ranges properties.
- Remove the panthor-system node-name restriction.
- Remove gpu-supply from the schema and example.
- Add an example with assignments for partition-capable GPU with four resource groups.
- Move theMAINTAINERSupdate to the GPU schema patch..../bindings/gpu/arm,mali-gen5-am-system.yaml | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yamlDocumentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +11
-0@@ -0,0 +1,196 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright 2026 ARM Limited. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am-system.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th-Gen GPU System Device + +maintainers: + - Liviu Dudau <[email protected]>
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 21
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +10
-0+ - Boris Brezillon <[email protected]> + +properties: + compatible: + items: + - const: arm,mali-gen5-am-system + + reg: + minItems: 1 + maxItems: 2
Why is this flexible? There is no description in the binding which would explain oddities in choices of hardware representation.
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +8
-0+ + reg-names: + minItems: 1 + items: + - const: system + - const: assign + + interrupts:
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 39
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +10
-0+ maxItems: 1 + + clocks: + maxItems: 1 + + dma-coherent: true + + "#address-cells": true + + "#size-cells": true
Both need to be const or enum.
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 43
Quoted 4 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +4
-0+ + ranges: true + + assignments:
Do not mix nodes with and without bus addressing. That's mess.
Quoted 60 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +60
-0+ type: object + additionalProperties: false + description: + Resource group HW resource assignment. Only valid for partition-capable + GPUs. + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + required: + - "#address-cells" + - "#size-cells" + + patternProperties: + "^resource-group@[0-3]$": + type: object + additionalProperties: false + + properties: + reg: + items: + - maximum: 3 + description: Resource group number. + + arm,axi-bus: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 1 + default: 0 + description: + Static resource-group to AXI bus assignment. Valid field values + are 0 for AXI_A and 1 for AXI_B. + + arm,partition-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xf + default: 0 + description: + Static partition-control to resource-group assignment. Bit N + selects partition control ID N. Mask must be disjoint across + resource groups. Unassigned partitions will be assigned to + resource group 0 by default. + + arm,slice-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xff + default: 0 + description: + Static slice to resource-group assignment. Bit N selects slice ID + N. Mask must be disjoint across resource groups. Unassigned slices + will be assigned to resource group 0 by default. + + arm,access-window-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xffff + default: 0 + description: + Static access-window to resource-group assignment. Bit N selects
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 113
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +10
-0+ access window ID N. Masks must be disjoint across resource groups. + Unassigned access-windows will be assigned to resource group 0 by + default. + + required: + - reg + +patternProperties: + '^gpu-arbitration@[a-f0-9]+$': + $ref: arm,mali-gen5-am-arbitration.yaml#
There is no such file. You did not really test it.
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 122
Quoted 9 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +9
-0+ +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + +additionalProperties: false
This goes after allOf: block.
Quoted 60 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +60
-0+ +allOf: + - if: + required: + - assignments + then: + properties: + reg: + minItems: 2 + reg-names: + minItems: 2 + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-system@68000000 { + compatible = "arm,mali-gen5-am-system"; + reg = <0x68000000 0x10000>; + reg-names = "system"; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mali_gpu_clk>; + }; + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-system@68000000 { + compatible = "arm,mali-gen5-am-system"; + reg = <0x68000000 0x10000>, <0x68010000 0x10000>; + reg-names = "system", "assign"; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mali_gpu_clk>; + + assignments { + #address-cells = <1>; + #size-cells = <0>; + + resource-group@0 { + reg = <0>; + arm,axi-bus = <0>; + arm,partition-mask = <0x1>; + arm,slice-mask = <0x3>; + arm,access-window-mask = <0xf>; + }; + + resource-group@1 { + reg = <1>; + arm,axi-bus = <0>; + arm,partition-mask = <0x2>; + arm,slice-mask = <0xc>; + arm,access-window-mask = <0xf0>; + }; + + resource-group@2 { + reg = <2>; + arm,axi-bus = <1>; + arm,partition-mask = <0x4>; + arm,slice-mask = <0x30>;
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 192
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +10
-0+ arm,access-window-mask = <0xf00>; + }; + + resource-group@3 { + reg = <3>; + arm,axi-bus = <1>; + arm,partition-mask = <0x8>; + arm,slice-mask = <0xc0>; + arm,access-window-mask = <0xf000>; + };
Your example is incomplete.
Best regards,
Krzysztof
Re: [PATCH v2 11/28] dt-bindings: gpu: panthor: Document AM system bindings
Quoted 49 lines · Krzysztof Kozlowski
Quoted 48 lines · Karunika Choo
Mali 5th-Gen AM GPUs expose an
AM_SYSTEMblock for GPU-wide control and theAM_ASSIGNblock for HW resource assignment outside the GPU job submission register window.Document the system node compatible, register and interrupt resources, GPU clock, and assignment properties for HW resource assignment.
Signed-off-by Karunika Choo <[email protected]>---
v2:
- Add an optionalAM_ASSIGNregister range. Require this range when the assignments node is present.
- Describe resource-group assignments for AXI buses, partitions, slices and access windows on partition-capable GPUs.
- Allow gpu-arbitration child nodes and the #address-cells, #size-cells and ranges properties.
- Remove the panthor-system node-name restriction.
- Remove gpu-supply from the schema and example.
- Add an example with assignments for partition-capable GPU with four resource groups.
- Move theMAINTAINERSupdate to the GPU schema patch..../bindings/gpu/arm,mali-gen5-am-system.yaml | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yamlDocumentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +16
-0@@ -0,0 +1,196 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright 2026 ARM Limited. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am-system.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th-Gen GPU System Device + +maintainers: + - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +properties: + compatible: + items:
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 21
Quoted 5 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +5
-0+ - const: arm,mali-gen5-am-system + + reg: + minItems: 1 + maxItems: 2Why is this flexible? There is no description in the binding which would explain oddities in choices of hardware representation.
I will restore the description that was previously asked to be dropped.
Quoted 21 lines
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +8
-0+ + reg-names: + minItems: 1 + items: + - const: system + - const: assign + + interrupts:Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 39
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +10
-0+ maxItems: 1 + + clocks: + maxItems: 1 + + dma-coherent: true + + "#address-cells": true + + "#size-cells": trueBoth need to be const or enum.
Quoted 6 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 43
Quoted 4 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +4
-0+ + ranges: true + + assignments:Do not mix nodes with and without bus addressing. That's mess.
Hi, I was asked to use a more generic DT such that should the hardware registers change in the future we can still retain some compatibility. Is it necessarily a problem?
Quoted 65 lines
Quoted 65 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +64
-0+ type: object + additionalProperties: false + description: + Resource group HW resource assignment. Only valid for partition-capable + GPUs. + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + required: + - "#address-cells" + - "#size-cells" + + patternProperties: + "^resource-group@[0-3]$": + type: object + additionalProperties: false + + properties: + reg: + items: + - maximum: 3 + description: Resource group number. + + arm,axi-bus: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 1 + default: 0 + description: + Static resource-group to AXI bus assignment. Valid field values + are 0 for AXI_A and 1 for AXI_B. + + arm,partition-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xf + default: 0 + description: + Static partition-control to resource-group assignment. Bit N + selects partition control ID N. Mask must be disjoint across + resource groups. Unassigned partitions will be assigned to + resource group 0 by default. + + arm,slice-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xff + default: 0 + description: + Static slice to resource-group assignment. Bit N selects slice ID + N. Mask must be disjoint across resource groups. Unassigned slices + will be assigned to resource group 0 by default. + + arm,access-window-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xffff + default: 0 + description: + Static access-window to resource-group assignment. Bit N selects + access window ID N. Masks must be disjoint across resource groups. + Unassigned access-windows will be assigned to resource group 0 by + default. +
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 113
Quoted 6 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +6
-0+ required: + - reg + +patternProperties: + '^gpu-arbitration@[a-f0-9]+$': + $ref: arm,mali-gen5-am-arbitration.yaml#There is no such file. You did not really test it.
Sorry, this was included from a later patch that introduces this file. I will move it there in v3.
Quoted 77 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 122
Quoted 10 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +9
-0+ +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + +additionalProperties: falseThis goes after allOf: block.
Quoted 64 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +64
-0+ +allOf: + - if: + required: + - assignments + then: + properties: + reg: + minItems: 2 + reg-names: + minItems: 2 + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-system@68000000 { + compatible = "arm,mali-gen5-am-system"; + reg = <0x68000000 0x10000>; + reg-names = "system"; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mali_gpu_clk>; + }; + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-system@68000000 { + compatible = "arm,mali-gen5-am-system"; + reg = <0x68000000 0x10000>, <0x68010000 0x10000>; + reg-names = "system", "assign"; + interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mali_gpu_clk>; + + assignments { + #address-cells = <1>; + #size-cells = <0>; + + resource-group@0 { + reg = <0>; + arm,axi-bus = <0>; + arm,partition-mask = <0x1>; + arm,slice-mask = <0x3>; + arm,access-window-mask = <0xf>; + }; + + resource-group@1 { + reg = <1>; + arm,axi-bus = <0>; + arm,partition-mask = <0x2>; + arm,slice-mask = <0xc>; + arm,access-window-mask = <0xf0>; + }; + + resource-group@2 { + reg = <2>; + arm,axi-bus = <1>; + arm,partition-mask = <0x4>; + arm,slice-mask = <0x30>; + arm,access-window-mask = <0xf00>; + }; + + resource-group@3 {
Quoted 8 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml line 192
Quoted 6 lines
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml new file +6
-0+ reg = <3>; + arm,axi-bus = <1>; + arm,partition-mask = <0x8>; + arm,slice-mask = <0xc0>; + arm,access-window-mask = <0xf000>; + };Your example is incomplete.
Could you clarify what specifically is missing?
Quoted 4 lines
Best regards,
Krzysztof
PATCH v2 12/28 drm/panthor: Add AM_SYSTEM platform driver
In reply to Karunika ChooMali v15 AM systems expose an AM_SYSTEM block for GPU-wide control.
Add a small AM_SYSTEM platform driver, wire it into Kconfig and the panthor build, and use it to manage the GPU clock and regulator resources. The driver also performs the initial GPU reset sequence during probe.
---
v2:
- Fix driver suspension during init unwind and termination paths.
- Handle cases where CONFIG_PM=n
- Fixes following issues raised by sashiko:
- Add rollback handling for failed regulator suspend.
- Use runtime pm ops macro
- Add module device table
- Link: https://lore.kernel.org/all/[email protected]/
- Register size comments are unsubstantiated.
v1:
- Renames panthor_system.c to panthor_system_drv.c to facilitate adding another source file for v15-AE support.
- Explicitly obtain named "system" IOMEM resource.
- Explicitly use "gpu-supply" regulator instead of inferring it from the "clock-names" DT property.
- Populate/depopulate child devices.
- Clear stale RESET_COMPLETED interrupts before reset.
drivers/gpu/drm/panthor/Kconfig | 10 + drivers/gpu/drm/panthor/Makefile | 1 + drivers/gpu/drm/panthor/system/Makefile | 13 + .../drm/panthor/system/panthor_system_drv.c | 344 ++++++++++++++++++ 4 files changed, 368 insertions(+) create mode 100644 drivers/gpu/drm/panthor/system/Makefile create mode 100644 drivers/gpu/drm/panthor/system/panthor_system_drv.c
drivers/gpu/drm/panthor/Kconfig +10 -0
@@ -20,3 +20,13 @@ config DRM_PANTHOR Note that the Mali-G68 and Mali-G78, while Valhall architecture, will be supported with the panfrost driver as they are not CSF GPUs. + +config DRM_PANTHOR_SYSTEM + tristate "GPU-wide configuration for Arm Mali 5th Gen AM GPUs" + depends on DRM_PANTHOR + depends on OF + help + Enable support for the AM_SYSTEM block found on Arm Mali 5th Gen + AM GPUs. This block provides GPU-wide control outside the main GPU + register window, including reset handling and management of shared + clock and regulator resources.
drivers/gpu/drm/panthor/Makefile +1 -0
@@ -14,5 +14,6 @@ panthor-y := \ panthor_sched.o obj-$(CONFIG_DRM_PANTHOR) += panthor.o +obj-$(CONFIG_DRM_PANTHOR_SYSTEM) += system/ CFLAGS_panthor_gpu.o := -I$(src)
drivers/gpu/drm/panthor/system/Makefile new file +13 -0
@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 OR MIT +# Copyright 2026 ARM Limited. All rights reserved. + +obj-$(CONFIG_DRM_PANTHOR_SYSTEM) += panthor_system.o + +panthor_system-y := \ + panthor_system_drv.o + +INCLUDES = \ + -I$(src)/.. + +ccflags-y += $(INCLUDES) +subdir-ccflags-y += $(INCLUDES)
drivers/gpu/drm/panthor/system/panthor_system_drv.c new file +344 -0
344 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 12/28] drm/panthor: Add AM_SYSTEM platform driver
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Low] drm/panthor: undocumented gpu-supply in panthor_system_regulator_init() --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Low] drm/panthor: undocumented gpu-supply in panthor_system_regulator_init()
--
commit 7d8058a58397fcb291163cb1ac726e2a1ba1d037
Author: Karunika Choo <[email protected]>
drm/panthor: Add AM_SYSTEM platform driver
This commit adds the AM_SYSTEM platform driver for Arm Mali 5th Gen AM GPUs to manage shared clock and regulator resources and perform the initial GPU reset sequence during probe.
Quoted 6 lines
drivers/gpu/drm/panthor/system/panthor_system_drv.c new file +0
-0@@ -0,0 +1,344 @@
[ ... ]
Quoted 5 lines
drivers/gpu/drm/panthor/system/panthor_system_drv.c new file +5
-0+static int panthor_system_regulator_init (struct panthor_system *sdev) +{ +struct regulator *regulator =NULL ; +int ret; +
drivers/gpu/drm/panthor/system/panthor_system_drv.c line 67
Quoted 10 lines
drivers/gpu/drm/panthor/system/panthor_system_drv.c new file +10
-0+ regulator =devm_regulator_get_optional (sdev->dev,"gpu" ); +if (IS_ERR (regulator)) { + ret =PTR_ERR (regulator); + +/* Regulator not found. Exit */ +if (ret == -ENODEV ) +return 0 ; + +return dev_err_probe (sdev->dev, ret,"Failed to get gpu-supply" ); + }
[Severity: Low]
Should gpu-supply be documented in Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-system.yaml? That schema sets additionalProperties: false without listing gpu-supply, so any arm,mali-gen5-am-system device tree node providing the regulator expected here will fail dtbs_check validation.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=12
PATCH v2 13/28 dt-bindings: gpu: panthor: Document panthor-arbitration bindings
In reply to Karunika ChooMali 5th-Gen AM GPUs expose partition-control and resource-group registers outside the GPU node.
Document named register and interrupt resources in the arbitration node. The pcN and rgN names identify the hardware blocks.
Document initial access-window and slice assignments in partition child nodes. The reg property identifies the partition-control index.
---
v2:
- Return to using named register and interrupt arrays instead of individual entries in child nodes.
- Added register and interrupt entries for partition-capable GPUs (rg[0-3], pc[0-3]).
- Introduce partition nodes to define default access-window and slice masks.
- Point child Panthor device node to new arm,mali-gen5-am.yaml
- Added partition-capable GPU example entry.
v2:
- Introduce assignment_lock to protect assignments allowing serialized lookup without the need for READ_ONCE or WRITE_ONCE.
- Add pending_aw_request_mask to track and replay pending requests arriving before AW assignments are initialized.
.../gpu/arm,mali-gen5-am-arbitration.yaml | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-arbitration.yaml
Documentation/devicetree/bindings/gpu/arm,mali-gen5-am-arbitration.yaml new file +198 -0
@@ -0,0 +1,198 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +# Copyright 2026 ARM Limited. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/arm,mali-gen5-am-arbitration.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Mali 5th-Gen GPU Arbitration Device + +maintainers: + - Liviu Dudau <[email protected]> + - Boris Brezillon <[email protected]> + +description: + The arbitration device manages GPU partition-control and resource-group + blocks. Register and interrupt names pcN and rgN identify their hardware + indices. Partition child nodes describe initial resource assignments, + with reg identifying the partition-control index. Access-window and slice + indices are global to the GPU, each resource may be assigned to at most one + partition. + +properties: + compatible: + const: arm,mali-gen5-am-arbitration + + reg: + minItems: 2 + maxItems: 8 + + reg-names: + minItems: 2 + maxItems: 8 + items: + enum: [pc0, pc1, pc2, pc3, rg0, rg1, rg2, rg3] + + interrupts: + minItems: 2 + maxItems: 8 + + interrupt-names: + minItems: 2 + maxItems: 8 + items: + enum: [pc0, pc1, pc2, pc3, rg0, rg1, rg2, rg3] + + "#address-cells": true + "#size-cells": true + ranges: true + + partitions: + type: object + additionalProperties: false + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + required: + - "#address-cells" + - "#size-cells" + + patternProperties: + "^partition@[0-3]$": + type: object + additionalProperties: false + description: + Initial partition resource assignments. + + properties: + reg: + items: + - maximum: 3 + description: Partition control number. + + arm,access-window-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xffff + default: 0 + description: + Initial access window assignment mask. Bit N selects global + access window ID N. Masks must be disjoint across partitions. + If omitted on partitioning-capable GPUs, no access windows are + assigned by default. Non-partitioning GPUs will have all AWs + assigned to pc0 if value is 0 or not defined. + + arm,slice-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xff + default: 0 + description: + Initial slice assignment mask. Bit N selects global slice ID N. + Masks must be disjoint across partitions. If omitted, no + partitions are created by default. This property is only valid for + partition-capable GPUs. + + required: + - reg + +patternProperties: + "^gpu@[0-9a-f]+$": + $ref: arm,mali-gen5-am.yaml# + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-arbitration@50000 { + compatible = "arm,mali-gen5-am-arbitration"; + reg = <0x50000 0x10000>, + <0xC0000 0x10000>; + reg-names = "pc0", "rg0"; + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "pc0", "rg0"; + + partitions { + #address-cells = <1>; + #size-cells = <0>; + + partition@0 { + reg = <0x0>; + arm,access-window-mask = <0xffff>; + }; + }; + }; + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpu-arbitration@40000 { + compatible = "arm,mali-gen5-am-arbitration"; + reg = <0x40000 0x10000>, + <0x50000 0x10000>, + <0xC0000 0x10000>; + reg-names = "pc0", "pc1", "rg0"; + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "pc0", "pc1", "rg0"; + + partitions { + #address-cells = <1>; + #size-cells = <0>; + + partition@0 { + reg = <0x0>; + arm,access-window-mask = <0xf>; + arm,slice-mask = <0x3>; + }; + partition@1 { + reg = <0x1>; + arm,access-window-mask = <0xf0>; + arm,slice-mask = <0xc>; + }; + }; + }; + + gpu-arbitration@60000 { + compatible = "arm,mali-gen5-am-arbitration"; + reg = <0x60000 0x10000>, + <0x70000 0x10000>, + <0xD0000 0x10000>; + reg-names = "pc2", "pc3", "rg1"; + interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH 0>, + <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "pc2", "pc3", "rg1"; + + partitions { + #address-cells = <1>; + #size-cells = <0>; + + partition@2 { + reg = <0x2>; + arm,access-window-mask = <0xf00>; + arm,slice-mask = <0x30>; + }; + partition@3 { + reg = <0x3>; + arm,access-window-mask = <0xf000>; + arm,slice-mask = <0xc0>; + }; + }; + }; + +...
Signature · 1 line
2.43.0
PATCH v2 14/28 drm/panthor: Add AM_PARTITION_CONTROL support
In reply to Karunika ChooMali v15 AM GPUs expose AM_PARTITION_CONTROL blocks to manage partition access windows.
Add a Panthor arbitration platform driver and connect it to Kconfig and the build system.
Get partition-control register ranges and interrupts from named resources of the arbitration device. Use pcN names to identify partition-control blocks.
Provide helpers to open, close and yield access windows.
---
v2:
- Revert child node discovery changes from v1 for register and interrupts.
- Fixes the following issues raised by sashiko:
- Use DEV_PM_OPS and MODULE_DEVICE_TABLE macros
- Change %llx to %pa for res.start
- Simplify and clean up runtime PM handling.
- Relax read_poll_timeout due to longer timeouts
- Extend pc->lock to state checks to serialize against state changes triggered by partition commands.
- Remove implicit close during window_open.
- CLOSE_WINDOW during termination only when runtime PM is available.
- Add irq_lock to prevent MMIO access as a result of shared IRQ while GPU is powered off.
- Add check for allocation failure from devm_kasprintf.
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- Updated DT structure and accompanying parsing to handle child nodes instead of named platform resources.
- Add child device population/depopulation.
- Remove blocking waits on partition open, close and yield operations.
- Adds YIELD_IDLE helper.
drivers/gpu/drm/panthor/Kconfig | 10 + drivers/gpu/drm/panthor/Makefile | 1 + drivers/gpu/drm/panthor/arbitration/Makefile | 13 + .../panthor/arbitration/panthor_arbitration.h | 27 ++ .../arbitration/panthor_arbitration_drv.c | 142 +++++++ .../arbitration/panthor_partition_control.c | 379 ++++++++++++++++++ .../arbitration/panthor_partition_control.h | 29 ++ 7 files changed, 601 insertions(+) create mode 100644 drivers/gpu/drm/panthor/arbitration/Makefile create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_partition_control.h
drivers/gpu/drm/panthor/Kconfig +10 -0
@@ -30,3 +30,13 @@ config DRM_PANTHOR_SYSTEM AM GPUs. This block provides GPU-wide control outside the main GPU register window, including reset handling and management of shared clock and regulator resources. + +config DRM_PANTHOR_ARBITRATION + tristate "HW-assisted virtualization for Mali 5th Gen AM GPUs" + depends on DRM_PANTHOR + depends on OF + help + Enable support for the arbitration blocks found on Arm Mali 5th Gen + AM GPUs. These blocks manage partition controls, resource groups and + access-window scheduling, allowing multiple access windows to share + GPU resources under hardware-assisted arbitration.
drivers/gpu/drm/panthor/Makefile +1 -0
@@ -15,5 +15,6 @@ panthor-y := \ obj-$(CONFIG_DRM_PANTHOR) += panthor.o obj-$(CONFIG_DRM_PANTHOR_SYSTEM) += system/ +obj-$(CONFIG_DRM_PANTHOR_ARBITRATION) += arbitration/ CFLAGS_panthor_gpu.o := -I$(src)
drivers/gpu/drm/panthor/arbitration/Makefile new file +13 -0
@@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 OR MIT +# Copyright 2026 ARM Limited. All rights reserved. + +obj-$(CONFIG_DRM_PANTHOR_ARBITRATION) += panthor_arbitration.o +panthor_arbitration-y := \ + panthor_arbitration_drv.o \ + panthor_partition_control.o + +INCLUDES = \ + -I$(src)/.. + +ccflags-y += $(INCLUDES) +subdir-ccflags-y += $(INCLUDES)
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h new file +27 -0
@@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_ARBITRATION_H__ +#define __PANTHOR_ARBITRATION_H__ + +#include <linux/ioport.h> +#include <linux/fwnode.h> + +struct device ; +struct panthor_partition_control ; + +#define AM_ARB_MAX_PC_COUNT 1 +#define AM_ARB_MAX_AW_COUNT 16 + +/** +* struct panthor_arbitration - Arbitration device +*/ +struct panthor_arbitration { +/** @dev: Device pointer */ +struct device *dev; + +/** @pc: Pointer array to partition control data */ +struct panthor_partition_control *pc[AM_ARB_MAX_PC_COUNT ]; +}; + +#endif
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c new file +142 -0
142 lines not on this page · raw message
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +379 -0
379 lines not on this page · raw message
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.h new file +29 -0
@@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_PARTITION_CONTROL_H__ +#define __PANTHOR_PARTITION_CONTROL_H__ + +#include <linux/types.h> + +struct device ; +struct panthor_arbitration ; +struct panthor_partition_control ; + +int panthor_partition_control_init (struct panthor_arbitration *adev); + +void panthor_partition_control_term (struct panthor_arbitration *adev); + +int panthor_partition_control_suspend (struct panthor_arbitration *adev); + +int panthor_partition_control_resume (struct panthor_arbitration *adev); + +int panthor_partition_control_open_window (struct panthor_partition_control *pc,u8 aw_id); + +int panthor_partition_control_close_window (struct panthor_partition_control *pc); + +int panthor_partition_control_yield_now (struct panthor_partition_control *pc); + +int panthor_partition_control_yield_idle (struct panthor_partition_control *pc); + +#endif
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 14/28] drm/panthor: Add AM_PARTITION_CONTROL support
Thank you for your contribution! Sashiko AI review found 4 potential issues to consider: - [Medium] drm/panthor: TOCTOU race from multiple AM_PART_STATE reads in window helpers - [Medium]…
Thank you for your contribution! Sashiko AI review found 4 potential issues to consider:
- [Medium] drm/panthor: TOCTOU race from multiple AM_PART_STATE reads in window helpers
- [Medium] drm/panthor: panthor_partition_control_term() fails on in-progress state transitions
- [Low] drm/panthor: unused devm allocations in partition_control_init() on -ENODEV
- [Low] drm/panthor: unchecked devm_kasprintf() in partition_control_init()
--
commit 9f7b5a10199859069acf5b5904f5b9aca326fc89
Author: Karunika Choo <[email protected]>
drm/panthor: Add AM_PARTITION_CONTROL support
This commit adds the Panthor arbitration platform driver and partition control support to manage access windows on Mali v15 AM GPUs.
Quoted 5 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +0
-0
[ ... ]
Quoted 13 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +13
-0+static u32 partition_state_get (struct panthor_partition_control *pc) +{ +const u32 state =gpu_read (pc->iomem,AM_PART_STATE ); + +return AM_PART_STATE_GET (state); +} + +static u8 partition_aw_get (struct panthor_partition_control *pc) +{ +const u32 state =gpu_read (pc->iomem,AM_PART_STATE ); + +return AM_PART_STATE_WINDOW_GET (state); +}
[ ... ]
Quoted 59 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +59
-0+static int yield_now (struct panthor_partition_control *pc) +{ +guard (spinlock_irqsave)(&pc->lock); + +if (partition_state_get (pc) ==PART_STATE_RESET ) +return 0 ; + +if (partition_state_get (pc) !=PART_STATE_WINDOW_OPEN ) +return -EAGAIN ; + +gpu_write (pc->iomem,AM_PART_COMMAND , +AM_PART_SET_COMMAND (PART_CMD_YIELD_NOW )); + +return 0 ; +} + +static int yield_idle (struct panthor_partition_control *pc) +{ +guard (spinlock_irqsave)(&pc->lock); + +if (partition_state_get (pc) ==PART_STATE_RESET ) +return 0 ; + +if (partition_state_get (pc) !=PART_STATE_WINDOW_OPEN ) +return -EAGAIN ; + +gpu_write (pc->iomem,AM_PART_COMMAND , +AM_PART_SET_COMMAND (PART_CMD_YIELD_IDLE )); + +return 0 ; +} + +static int window_close (struct panthor_partition_control *pc) +{ +guard (spinlock_irqsave)(&pc->lock); + +if (partition_state_get (pc) ==PART_STATE_RESET ) +return 0 ; + +if (partition_state_get (pc) !=PART_STATE_WINDOW_OPEN ) +return -EAGAIN ; + + pc->closing = true; + +gpu_write (pc->iomem,AM_PART_COMMAND , +AM_PART_SET_COMMAND (PART_CMD_CLOSE_WINDOW )); + +return 0 ; +} + +static int window_open (struct panthor_partition_control *pc,u8 aw_id) +{ +if (aw_id >=AM_ARB_MAX_AW_COUNT ) +return -EINVAL ; + +guard (spinlock_irqsave)(&pc->lock); + +if (partition_state_get (pc) ==PART_STATE_WINDOW_OPEN ) { +u8 cur_aw =partition_aw_get (pc);
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c line 189
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +10
-0+ +if (cur_aw == aw_id) +return 0 ; + +dev_warn (pc->dev, +"%s: OPEN_WINDOW(%u): Already opened for aw=%u, state=%u. Closing..." , + pc->name, aw_id, cur_aw,partition_state_get (pc)); + +return -EBUSY ; + }
[Severity: Medium]
Can an asynchronous hardware state transition between these back-to-back AM_PART_STATE reads cause yield_now(), yield_idle(), window_close(), and window_open() to act on inconsistent state?
Each call to partition_state_get() and partition_aw_get() performs a separate MMIO read of AM_PART_STATE. If the partition finishes closing or yielding and transitions into PART_STATE_RESET between the first and second partition_state_get() in yield_now(), yield_idle(), or window_close(), the first check is false and the second sees PART_STATE_RESET != PART_STATE_WINDOW_OPEN, returning -EAGAIN instead of 0 (which in panthor_partition_control_term() triggers WARN_ON() and skips partition_state_wait()). In window_open(), if the partition resets between partition_state_get() and partition_aw_get(), cur_aw reads as 0; when aw_id is 0, window_open() returns 0 without issuing PART_CMD_OPEN_WINDOW.
Also, the dev_warn() in window_open() performs a third MMIO read of AM_PART_STATE and still says "Closing..." even though window_open() no longer closes the window. Reading AM_PART_STATE once into a local variable under pc->lock and extracting both fields from that value would avoid these races.
[ ... ]
Quoted 5 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +5
-0+void panthor_partition_control_term (struct panthor_arbitration *adev) +{ +for (int i =0 ; i <AM_ARB_MAX_PC_COUNT ; i++) { +struct panthor_partition_control *pc = adev->pc[i]; +
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c line 277
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +10
-0+if (!pc) +continue ; + +partition_irq_suspend (pc); + +if (!pm_runtime_status_suspended (pc->dev)) +if (!WARN_ON (window_close (pc) <0 )) +WARN_ON (partition_state_wait (pc,PART_STATE_RESET )); + } +}
[Severity: Medium]
What happens in panthor_partition_control_term() if a partition is already transitioning through PART_STATE_WINDOW_CLOSED or PART_STATE_WINDOW_OPENING when teardown runs?
window_open(), window_close(), yield_now(), and yield_idle() issue commands without waiting for the state transition to complete, and window_close() returns -EAGAIN for any state other than PART_STATE_RESET and PART_STATE_WINDOW_OPEN. If a transition is still in flight when panthor_partition_control_term() runs, window_close() returns -EAGAIN, triggering WARN_ON() and skipping partition_state_wait() while the hardware is still active. Commit "drm/panthor: Reset partitions before starting arbitration" later in this series adds partition_ensure_reset() to handle in-progress states during init, so calling it here as well would ensure teardown waits for the reset to complete.
Quoted 18 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +18
-0+static int partition_control_init (struct panthor_arbitration *adev,int i) +{ +struct panthor_partition_control *pc; +struct device *dev = adev->dev; +struct irq_data *irqdata; +struct resource *res; +void __iomem *iomem; +u32 irq_flags =0 ; +char *name; +int irq; +int ret; + +if (adev->pc[i]) +return dev_warn_probe (dev, -ENODEV , +"partition %u already present" , i); + + pc =devm_kzalloc (dev,sizeof (*pc),GFP_KERNEL ); +if (!pc)
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c line 306
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +10
-0+return -ENOMEM ; + + name =devm_kasprintf (dev,GFP_KERNEL ,"pc%d" , i); +if (!name) +return -ENOMEM ; + + res =platform_get_resource_byname (to_platform_device (dev), +IORESOURCE_MEM , name); +if (!res) +return -ENODEV ;
[Severity: Low]
When platform_get_resource_byname() finds no resource and returns -ENODEV, panthor_partition_control_init() ignores -ENODEV and probe succeeds, leaving pc and name allocated on dev until the driver unbinds. Could pc be allocated after looking up res (or the unused devm allocations be freed before returning -ENODEV)?
[ ... ]
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c line 336
Quoted 5 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c new file +5
-0+ ret =devm_request_irq ( + dev, irq, partition_irq_raw_handler, irq_flags |IRQF_SHARED , +devm_kasprintf (dev,GFP_KERNEL ,"panthor-%s-irq" , name), pc); +if (ret) +return ret;
[Severity: Low]
Can devm_kasprintf() return NULL here and pass a NULL devname into devm_request_irq() instead of failing with -ENOMEM?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=14
kernel test robot
build botRe: [PATCH v2 14/28] drm/panthor: Add AM_PARTITION_CONTROL support
In reply to Karunika Chookernel test robot noticed the following build errors:
Hi Karunika,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-misc/drm-misc-next]
[also build test ERROR on drm/drm-next drm-tip/drm-tip next-20261110]
[cannot apply to linux-review/Karunika-Choo/drm-panthor-Ignore-EOPNOTSUPP-for-shader-present-nvmem-lookup/20260922-214455 daeinki-drm-exynos/exynos-drm-next drm-i915/for-linux-next drm-i915/for-linux-next-fixes linus/master v7.4-rc2] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Karunika-Choo/drm-panthor-Ignore-EOPNOTSUPP-for-shader-present-nvmem-lookup/20261110-153822 base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next patch link: https://lore.kernel.org/r/20261110153907.3241978-15-karunika.choo%40arm.com patch subject: [PATCH v2 14/28] drm/panthor: Add AM_PARTITION_CONTROL support config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20261111/[email protected]/config) compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project e73e336290028f26553b46c9fba844c13da38c9c) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261111/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:328:12: error: call to undeclared function 'irq_get_irq_data'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
328 | irqdata = irq_get_irq_data(irq);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:328:12: note: did you mean 'irq_set_irq_wake'?
include/linux/interrupt.h:486:12: note: 'irq_set_irq_wake' declared here
486 | extern int irq_set_irq_wake(unsigned int irq, unsigned int on);
| ^
>> drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:328:10: error: incompatible integer to pointer conversion assigning to 'struct irq_data *' from 'int' [-Wint-conversion]
328 | irqdata = irq_get_irq_data(irq);
| ^ ~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:330:15: error: call to undeclared function 'irqd_get_trigger_type'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
330 | irq_flags = irqd_get_trigger_type(irqdata);
| ^3 errors generated.
vim +/irq_get_irq_data +328 drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c
278
279 static int partition_control_init(struct panthor_arbitration *adev, int i)
280 {
281 struct panthor_partition_control *pc;
282 struct device *dev = adev->dev;
283 struct irq_data *irqdata;
284 struct resource *res;
285 void __iomem *iomem;
286 u32 irq_flags = 0;
287 char *name;
288 int irq;
289 int ret;
290
291 if (adev->pc[i])
292 return dev_warn_probe(dev, -ENODEV,
293 "partition %u already present", i);
294
295 pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
296 if (!pc)
297 return -ENOMEM;
298
299 name = devm_kasprintf(dev, GFP_KERNEL, "pc%d", i);
300 if (!name)
301 return -ENOMEM;
302
303 res = platform_get_resource_byname(to_platform_device(dev),
304 IORESOURCE_MEM, name);
305 if (!res)
306 return -ENODEV;
307
308 iomem = devm_ioremap_resource(dev, res);
309 if (IS_ERR(iomem))
310 return dev_err_probe(dev, PTR_ERR(iomem), "%s: Failed to ioremap", name);
311
312 pc->name = name;
313 pc->dev = dev;
314 pc->iomem = iomem;
315
316 spin_lock_init(&pc->irq_lock);
317 pc->irq_suspended = true;
318
319 spin_lock_init(&pc->lock);
320 pc->current_aw = AW_UNASSIGNED;
321
322 irq = platform_get_irq_byname(to_platform_device(dev), name);
323 if (irq < 0)
324 return irq;
325
326 pc->irq = irq;
327
> 328 irqdata = irq_get_irq_data(irq); 329 if (irqdata) > 330 irq_flags = irqd_get_trigger_type(irqdata);
331
332 ret = devm_request_irq(
333 dev, irq, partition_irq_raw_handler, irq_flags | IRQF_SHARED,
334 devm_kasprintf(dev, GFP_KERNEL, "panthor-%s-irq", name), pc);
335 if (ret)
336 return ret;
337
338 adev->pc[i] = pc;
339
340 partition_irq_resume(pc);
341
342 return 0;
343 }
344
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
PATCH v2 15/28 drm/panthor: Add AM message helpers
In reply to Karunika ChooAdd a shared helper layer for the AM_MESSAGE registers used by v15 GPUs to coordinate between access windows to enable virtualisation of the GPU.
The helper defines message IDs, register accessors, version negotiation, and FIFO-backed sending. Outgoing messages are serialized with a spinlock, written in the required register order, and queued for later retry when the hardware outgoing slot is busy.
---
v2:
- Tighten protocol validation flow by separating the remote version and reply_version to allow local validation of protocol support.
v1:
- Raises minimum/current protocol support to v2. (v1 was for G78AE)
- Removes ARB_VM_GPU_STOP.
- Return -ENOSPC instead of -ENOMEM on full outgoing FIFO.
drivers/gpu/drm/panthor/panthor_am_msg.h | 182 +++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 drivers/gpu/drm/panthor/panthor_am_msg.h
drivers/gpu/drm/panthor/panthor_am_msg.h new file +182 -0
@@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_AM_H__ +#define __PANTHOR_AM_H__ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/kfifo.h> +#include <linux/types.h> + +#include "panthor_device_io.h" + +/* Protocol versioning */ +#define ARB_VM_PROTOCOL_V1 0x1 +#define ARB_VM_PROTOCOL_V2 0x2 + +#define AM_MSG_MIN_SUPPORTED_VERSION ARB_VM_PROTOCOL_V2 +#define AM_MSG_CURRENT_VERSION ARB_VM_PROTOCOL_V2 + +#define AM_INCOMING_MESSAGE0 0x0 +#define AM_INCOMING_MESSAGE1 0x4 +#define AM_OUTGOING_MESSAGE_STATUS 0x8 +#define AM_OUTGOING_MESSAGE0 0xc +#define AM_OUTGOING_MESSAGE1 0x10 + +/* Arbiter to VM message IDs */ +#define ARB_VM_INIT 0x04 + +/* VM to Arbiter message IDs */ +#define VM_ARB_INIT 0x05 +#define VM_ARB_GPU_REQUEST 0x08 +#define VM_ARB_GPU_STOPPED 0x09 + +#define AM_MSG_ID_MASK GENMASK(7, 0) +#define AM_MSG_ACK_MASK BIT(8) +#define AM_MSG_VERSION_MASK GENMASK(15, 9) + +#define AM_MSG_ID_GET (x) FIELD_GET(AM_MSG_ID_MASK, x) +#define AM_MSG_ACK_GET (x) FIELD_GET(AM_MSG_ACK_MASK, x) +#define AM_MSG_VERSION_GET (x) FIELD_GET(AM_MSG_VERSION_MASK, x) + +#define AM_MSG_INIT_MAKE (_id, _ack, _version) \ + ((_id) | FIELD_PREP(AM_MSG_ACK_MASK, _ack) | FIELD_PREP(AM_MSG_VERSION_MASK, _version)) + +#define ARB_VM_INIT_MAKE (_ack, _version) AM_MSG_INIT_MAKE(ARB_VM_INIT, _ack, _version) +#define VM_ARB_INIT_MAKE (_ack, _version) AM_MSG_INIT_MAKE(VM_ARB_INIT, _ack, _version) + +#define AM_MSG_DEFAULT_FIFO_SIZE 4 + +struct panthor_am_msg { +/** @iomem: CPU mapping of the AM_MESSAGE registers */ +void __iomem *iomem; + +/** @lock: Lock for send_fifo and outgoing message register */ +spinlock_t lock; + +/** @send_fifo: FIFO to queue of messages to send */ + DECLARE_KFIFO(send_fifo, u64, AM_MSG_DEFAULT_FIFO_SIZE); + +/** @version: Protocol version */ +u8 version; +}; + +static inline void panthor_am_msg_init (struct panthor_am_msg *msg, +void __iomem *iomem) +{ +spin_lock_init (&msg->lock); +INIT_KFIFO (msg->send_fifo); + msg->iomem = iomem; + msg->version =0 ; +} + +static inline bool panthor_am_msg_pending (struct panthor_am_msg *msg) +{ +return !!gpu_read (msg->iomem,AM_OUTGOING_MESSAGE_STATUS ); +} + +static inline u64 panthor_am_msg_read (struct panthor_am_msg *msg) +{ +return gpu_read64 (msg->iomem,AM_INCOMING_MESSAGE0 ); +} + +static inline void panthor_am_msg_write (struct panthor_am_msg *msg,u64 message) +{ +lockdep_assert_held (&msg->lock); + +/* +* Registers must be written in this exact order to prevent interrupts +* being raised before the complete message is written. +*/ +gpu_write (msg->iomem,AM_OUTGOING_MESSAGE0 ,lower_32_bits (message)); +gpu_write (msg->iomem,AM_OUTGOING_MESSAGE1 ,upper_32_bits (message)); +} + +static inline int panthor_am_msg_retry (struct panthor_am_msg *msg) +{ +u64 message; + +guard (spinlock_irqsave)(&msg->lock); + +if (kfifo_is_empty (&msg->send_fifo)) +return 0 ; + +if (panthor_am_msg_pending (msg)) +return -EBUSY ; + +/* FIFO should never be empty at this point */ +if (!kfifo_get (&msg->send_fifo, &message)) +return -EINVAL ; + +panthor_am_msg_write (msg, message); + +/* There are still messages in the FIFO, notify caller to retry again */ +if (!kfifo_is_empty (&msg->send_fifo)) +return -EAGAIN ; + +return 0 ; +} + +static inline int panthor_am_msg_send (struct panthor_am_msg *msg,u64 message) +{ +guard (spinlock_irqsave)(&msg->lock); + +/* +* If there already is a pending message in the FIFO or the outgoing +* message is still not read by the receipient, add to the FIFO. +*/ +if (!kfifo_is_empty (&msg->send_fifo) ||panthor_am_msg_pending (msg)) { +if (!kfifo_put (&msg->send_fifo, message)) +return -ENOSPC ; + +/* +* return -EBUSY to indicate to the caller to schedule work to +* retry sending messages in the FIFO. +*/ +return -EBUSY ; + } + +/* We are free to write to AM_OUTGOING_MESSAGE */ +panthor_am_msg_write (msg, message); + +return 0 ; +} + +static inline int panthor_am_msg_version_validate (struct panthor_am_msg *msg, +u8 version,bool acked, +u8 *reply_version) +{ +guard (spinlock_irqsave)(&msg->lock); + +if (reply_version ==NULL ) +return -EINVAL ; + + msg->version = version; + +if (version <AM_MSG_MIN_SUPPORTED_VERSION ) { + *reply_version =AM_MSG_MIN_SUPPORTED_VERSION ; +return -EOPNOTSUPP ; + } + +if (acked && version >AM_MSG_CURRENT_VERSION ) { + *reply_version =AM_MSG_CURRENT_VERSION ; +return -EOPNOTSUPP ; + } + + msg->version =min (version,AM_MSG_CURRENT_VERSION ); + *reply_version = msg->version; + +return 0 ; +} + +static inline bool panthor_am_msg_supported (struct panthor_am_msg *msg) +{ +guard (spinlock_irqsave)(&msg->lock); + +return msg->version >=AM_MSG_MIN_SUPPORTED_VERSION && + msg->version <=AM_MSG_CURRENT_VERSION ; +} + +#endif
Signature · 1 line
2.43.0
PATCH v2 16/28 drm/panthor: Add AM_RESOURCE_GROUP support
In reply to Karunika ChooAdd resource-group probing for the arbitration device, including MMIO resources, IRQ handling, per-AW AM message helpers, handshake negotiation, and retry work for deferred outgoing messages.
Hook resource groups into arbitration init, teardown, and runtime PM.
---
v2:
- Revert child node parsing from v1.
- Tighten protocol validation and reject incompatible messages.
- Drain pending messages on suspend.
- Fixes the following issues raised by sashiko:
- Simplify and clean up rutnime PM handling and termination paths.
- change message retry work to delayed work.
- Add irq_lock to prevent MMIO access as a result of shared IRQ while GPU is powered off.
- Fix irq number storage.
- Add check for allocation failure from devm_kasprintf
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- Updated DT structure and accompanying parsing to handle child nodes instead of named platform resources.
- Hold runtime PM reference during message retries.
- Fix suspend resume ordering.
drivers/gpu/drm/panthor/arbitration/Makefile | 3 +- .../panthor/arbitration/panthor_arbitration.h | 5 + .../arbitration/panthor_arbitration_drv.c | 15 + .../arbitration/panthor_resource_group.c | 373 ++++++++++++++++++ .../arbitration/panthor_resource_group.h | 20 + 5 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_resource_group.h
drivers/gpu/drm/panthor/arbitration/Makefile +2 -1
@@ -4,7 +4,8 @@ obj-$(CONFIG_DRM_PANTHOR_ARBITRATION) += panthor_arbitration.o panthor_arbitration-y := \ panthor_arbitration_drv.o \ - panthor_partition_control.o + panthor_partition_control.o \ + panthor_resource_group.o INCLUDES = \ -I$(src)/..
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h +5 -0
@@ -9,8 +9,10 @@struct device ;struct panthor_partition_control ; +struct panthor_resource_group ;#define AM_ARB_MAX_PC_COUNT 1 +#define AM_ARB_MAX_RG_COUNT 1#define AM_ARB_MAX_AW_COUNT 16/**
@@ -22,6 +24,9 @@ struct panthor_arbitration {/** @pc: Pointer array to partition control data */ struct panthor_partition_control *pc[AM_ARB_MAX_PC_COUNT ]; + +/** @rg: Pointer array to resource group data */ + struct panthor_resource_group *rg[AM_ARB_MAX_RG_COUNT]; };#endif
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +15 -0
@@ -12,6 +12,7 @@#include "panthor_arbitration.h" #include "panthor_partition_control.h" +#include "panthor_resource_group.h" #define PANTHOR_PM_AUTOSUSPEND_DELAY_MS 100
@@ -20,6 +21,10 @@ static int panthor_arbitration_runtime_suspend(struct device *dev)struct panthor_arbitration *adev =dev_get_drvdata (dev);int ret =0 ; + ret =panthor_resource_group_suspend (adev); +if (ret) +return ret; + ret =panthor_partition_control_suspend (adev);if (ret)return ret;
@@ -36,6 +41,10 @@ static int panthor_arbitration_runtime_resume(struct device *dev)if (ret)return ret; + ret =panthor_resource_group_resume (adev); +if (ret) +return ret; +return 0 ; }
@@ -66,6 +75,10 @@ static int panthor_arbitration_probe(struct platform_device *pdev)if (ret) goto err_term; + ret =panthor_resource_group_init (adev); +if (ret) + goto err_term; + ret =of_platform_populate (dev->of_node,NULL ,NULL , dev);if (ret) goto err_depopulate;
@@ -81,6 +94,7 @@ static int panthor_arbitration_probe(struct platform_device *pdev)of_platform_depopulate (dev); err_term: +panthor_resource_group_term (adev);panthor_partition_control_term (adev);pm_runtime_put_sync_suspend (dev);
@@ -106,6 +120,7 @@ static void panthor_arbitration_remove(struct platform_device *pdev)pm_runtime_disable (adev->dev);panthor_partition_control_term (adev); +panthor_resource_group_term (adev);if (ret >=0 )pm_runtime_put_noidle (adev->dev);
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c new file +373 -0
373 lines not on this page · raw message
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.h new file +20 -0
@@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_RESOURCE_GROUP_H__ +#define __PANTHOR_RESOURCE_GROUP_H__ + +#include <linux/types.h> + +struct device ; +struct panthor_arbitration ; + +int panthor_resource_group_init (struct panthor_arbitration *adev); + +void panthor_resource_group_term (struct panthor_arbitration *adev); + +int panthor_resource_group_suspend (struct panthor_arbitration *adev); + +int panthor_resource_group_resume (struct panthor_arbitration *adev); + +#endif
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 16/28] drm/panthor: Add AM_RESOURCE_GROUP support
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Medium] drm/panthor: lost AW message interrupt in rg_irq_raw_handler() --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Medium] drm/panthor: lost AW message interrupt in rg_irq_raw_handler()
--
commit 4a3c9d76bb48fcfdcf16aaac9521c7316fca8936
Author: Karunika Choo <[email protected]>
drm/panthor: Add AM_RESOURCE_GROUP support
This commit adds resource-group support to the Panthor arbitration driver, including MMIO and IRQ setup, per-access-window message handling, handshake negotiation, and runtime PM callbacks.
Quoted 5 lines
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c new file +0
-0
[ ... ]
Quoted 36 lines
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c new file +36
-0+static irqreturn_t rg_irq_raw_handler (int irq,void *data) +{ +struct panthor_resource_group *rg = data; +unsigned long message_mask; +u32 status; +u8 aw_id; + + scoped_guard(spinlock_irqsave, &rg->irq_lock) { +if (rg->irq_suspended) +return IRQ_NONE ; + } + + status =gpu_read (rg->iomem,AM_RG_IRQ_STATUS ); +if (!status) +return IRQ_NONE ; + + message_mask = status; +for_each_set_bit (aw_id, &message_mask,AM_ARB_MAX_AW_COUNT ) { +u64 message =panthor_am_msg_read (&rg->aw_data[aw_id].msg); + +rg_handle_message (rg, aw_id, message); + } + +gpu_write (rg->iomem,AM_RG_IRQ_CLEAR , status); + +return IRQ_HANDLED ; +} + +static void rg_drain_pending_messages (struct panthor_resource_group *rg) +{ +unsigned long message_mask; +u8 aw_id; + +if (pm_runtime_status_suspended (rg->dev)) +return ; +
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c line 222
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c new file +10
-0+ message_mask =gpu_read (rg->iomem,AM_RG_IRQ_RAWSTAT ) &AM_RG_MESSAGE_MASK ; + +for_each_set_bit (aw_id, &message_mask,AM_ARB_MAX_AW_COUNT ) { +u64 message =panthor_am_msg_read (&rg->aw_data[aw_id].msg); + +rg_handle_message (rg, aw_id, message); + } + +gpu_write (rg->iomem,AM_RG_IRQ_CLEAR , message_mask); +}
[Severity: Medium]
Can writing AM_RG_IRQ_CLEAR after the loop in rg_irq_raw_handler() and rg_drain_pending_messages() clear a follow-up access-window interrupt before its message is read?
When rg_handle_message() processes an unacknowledged VM_ARB_INIT from an access window, rg_respond_to_handshake() immediately sends ARB_VM_INIT back to that access window before the loop finishes and writes AM_RG_IRQ_CLEAR:
CPU0 (resource group) CPU1 / VM (access window aw_id)rg_irq_raw_handler()
status = gpu_read(AM_RG_IRQ_STATUS)
panthor_am_msg_read()
rg_handle_message()
rg_respond_to_handshake()
rg_send_init_msg(ARB_VM_INIT)
receives ARB_VM_INIT
sends VM_ARB_GPU_REQUEST (asserts BIT(aw_id) in AM_RG_IRQ_RAWSTAT)
gpu_write(AM_RG_IRQ_CLEAR, status)
<-- clears BIT(aw_id) without reading VM_ARB_GPU_REQUEST
If the hardware also keeps the sender's AM_OUTGOING_MESSAGE_STATUS busy until AM_RG_IRQ_CLEAR is written, delaying the clear until after rg_handle_message() leaves the access window's outgoing slot busy while it handles the reply. In either case, a missed VM_ARB_GPU_REQUEST or VM_ARB_GPU_STOPPED stalls GPU access acquisition or partition scheduling until the request timeout expires.
Clearing BIT(aw_id) in AM_RG_IRQ_CLEAR right after panthor_am_msg_read() and before rg_handle_message() would avoid this race.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=16
kernel test robot
build botRe: [PATCH v2 16/28] drm/panthor: Add AM_RESOURCE_GROUP support
In reply to Karunika Chookernel test robot noticed the following build errors:
Hi Karunika,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-misc/drm-misc-next]
[also build test ERROR on drm/drm-next drm-tip/drm-tip next-20261110]
[cannot apply to linux-review/Karunika-Choo/drm-panthor-Ignore-EOPNOTSUPP-for-shader-present-nvmem-lookup/20260922-214455 daeinki-drm-exynos/exynos-drm-next drm-i915/for-linux-next drm-i915/for-linux-next-fixes linus/master v7.4-rc2] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Karunika-Choo/drm-panthor-Ignore-EOPNOTSUPP-for-shader-present-nvmem-lookup/20261110-153822 base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next patch link: https://lore.kernel.org/r/20261110153907.3241978-17-karunika.choo%40arm.com patch subject: [PATCH v2 16/28] drm/panthor: Add AM_RESOURCE_GROUP support config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20261111/[email protected]/config) compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project e73e336290028f26553b46c9fba844c13da38c9c) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261111/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c:341:12: error: call to undeclared function 'irq_get_irq_data'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
341 | irqdata = irq_get_irq_data(irq);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c:341:12: note: did you mean 'irq_set_irq_wake'?
include/linux/interrupt.h:486:12: note: 'irq_set_irq_wake' declared here
486 | extern int irq_set_irq_wake(unsigned int irq, unsigned int on);
| ^
>> drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c:341:10: error: incompatible integer to pointer conversion assigning to 'struct irq_data *' from 'int' [-Wint-conversion]
341 | irqdata = irq_get_irq_data(irq);
| ^ ~~~~~~~~~~~~~~~~~~~~~
>> drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c:343:15: error: call to undeclared function 'irqd_get_trigger_type'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
343 | irq_flags = irqd_get_trigger_type(irqdata);
| ^3 errors generated.
vim +/irq_get_irq_data +341 drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c
284
285 static int resource_group_init(struct panthor_arbitration *adev, int i)
286 {
287 struct panthor_resource_group *rg;
288 struct device *dev = adev->dev;
289 struct irq_data *irqdata;
290 struct resource *res;
291 void __iomem *iomem;
292 u32 irq_flags = 0;
293 char *name;
294 int irq;
295 int ret;
296
297 if (adev->rg[i])
298 return dev_warn_probe(dev, -ENODEV,
299 "resource-group %u already present", i);
300
301 rg = devm_kzalloc(dev, sizeof(*rg), GFP_KERNEL);
302 if (!rg)
303 return -ENOMEM;
304
305 name = devm_kasprintf(dev, GFP_KERNEL, "rg%d", i);
306 if (!name)
307 return -ENOMEM;
308
309 res = platform_get_resource_byname(to_platform_device(dev),
310 IORESOURCE_MEM, name);
311 if (!res)
312 return -ENODEV;
313
314 iomem = devm_ioremap_resource(dev, res);
315 if (IS_ERR(iomem))
316 return dev_err_probe(dev, PTR_ERR(iomem), "%s: Failed to ioremap", name);
317
318 rg->name = name;
319 rg->dev = dev;
320 rg->iomem = iomem;
321
322 spin_lock_init(&rg->irq_lock);
323 rg->irq_suspended = true;
324
325 rg->wq = devm_alloc_ordered_workqueue(dev, "panthor-%s-wq", WQ_FREEZABLE, name);
326 if (!rg->wq)
327 return -ENOMEM;
328
329 INIT_DELAYED_WORK(&rg->msg_retry_work, rg_retry_messages);
330
331 for (int i = 0; i < AM_ARB_MAX_AW_COUNT; i++)
332 panthor_am_msg_init(&rg->aw_data[i].msg,
333 rg->iomem + AM_RG_AW_MESSAGE(i));
334
335 irq = platform_get_irq_byname(to_platform_device(dev), name);
336 if (irq < 0)
337 return irq;
338
339 rg->irq = irq;
340
> 341 irqdata = irq_get_irq_data(irq); 342 if (irqdata) > 343 irq_flags = irqd_get_trigger_type(irqdata);
344
345 ret = devm_request_irq(
346 dev, irq, rg_irq_raw_handler, irq_flags | IRQF_SHARED,
347 devm_kasprintf(dev, GFP_KERNEL, "panthor-%s-irq", name), rg);
348 if (ret)
349 return ret;
350
351 adev->rg[i] = rg;
352
353 rg_irq_resume(rg);
354
355 rg_handshake_init(rg);
356
357 return 0;
358 }
359
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
PATCH v2 17/28 drm/panthor: Add arbitration scheduler
In reply to Karunika ChooAdd a per-partition scheduler that queues access-window GPU requests and grants GPU access to queued windows in turn.
An uncontended access window can retain access after its timeslice expires. The scheduler requests a yield when the timeslice has expired and another window is waiting and force-closes the active window if it does not yield in time.
Use hrtimers for GPU timeslices and stop/close completion deadlines. Start stop and close timers after successful command submission.
Retry stop and close commands from workqueue context when submission returns -EAGAIN. Use scheduler reset work to recover from other command errors and completion timeouts.
---
v2:
- Use sched_id instead of looking it up via the aw_id for sched to AW operations.
- Fix stale timer callback from running on a newer lease generation.
- Fix following issues raised by sashiko:
- Simplify scheduler tear-down path.
- Fix timeout value truncation.
- Introduce retry path for commands that fail due to possibility of partition commands being rejected due to transient state transition.
- Add check for allocation failure from devm_kasprintf
- Rollback failed suspend / resume.
- Link: https://lore.kernel.org/all/[email protected]/
v1:
- Move grant, stop and close operations from workqueues into IRQ-safe paths. Retains work for scheduler recovery.
- Add closing phase and timer to ensure CLOSE_WINDOW completes in due time, otherwise enter recovery handling.
- Rename "grant_timeout_us" to "request_timeout" and "yield_timeout_us" to "yield_timeout". Both units are now in milliseconds.
- Add ABI documentation
.../testing/sysfs-driver-panthor-arbitration | 18 + MAINTAINERS | 1 + drivers/gpu/drm/panthor/arbitration/Makefile | 1 + .../panthor/arbitration/panthor_arbitration.h | 9 + .../arbitration/panthor_arbitration_drv.c | 31 + .../arbitration/panthor_arbitration_sched.c | 838 ++++++++++++++++++ .../arbitration/panthor_arbitration_sched.h | 38 + 7 files changed, 936 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-panthor-arbitration create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c create mode 100644 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.h
Documentation/ABI/testing/sysfs-driver-panthor-arbitration new file +18 -0
@@ -0,0 +1,18 @@ +What: /sys/module/panthor_arbitration/parameters/request_timeout +Date: September 2026 +KernelVersion: 7.2.0 +Contact: Arm Ltd. +Description: + Controls how long, in milliseconds, the arbitration scheduler + allows an access window to keep the GPU before asking it to + yield when another access window is waiting. + +What: /sys/module/panthor_arbitration/parameters/yield_timeout +Date: September 2026 +KernelVersion: 7.2.0 +Contact: Arm Ltd. +Description: + Controls how long, in milliseconds, the arbitration scheduler + waits for an access window to yield the GPU after a stop request. + If the timeout expires, the scheduler force-closes the access + window.
MAINTAINERS +1 -0
@@ -2400,6 +2400,7 @@ M: Liviu Dudau <[email protected]> L: [email protected] S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/ABI/testing/sysfs-driver-panthor-arbitration F: Documentation/devicetree/bindings/gpu/arm,mali-gen5-am*.yaml F: Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml F: drivers/gpu/drm/ci/xfails/panthor*
drivers/gpu/drm/panthor/arbitration/Makefile +1 -0
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_PANTHOR_ARBITRATION) += panthor_arbitration.o panthor_arbitration-y := \ panthor_arbitration_drv.o \ + panthor_arbitration_sched.o \ panthor_partition_control.o \ panthor_resource_group.o
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h +9 -0
@@ -6,8 +6,10 @@#include <linux/ioport.h> #include <linux/fwnode.h> +#include <linux/types.h> struct device ; +struct panthor_arbitration_sched ;struct panthor_partition_control ;struct panthor_resource_group ;
@@ -27,6 +29,13 @@ struct panthor_arbitration {/** @rg: Pointer array to resource group data */ struct panthor_resource_group *rg[AM_ARB_MAX_RG_COUNT ]; + +/** @sched: Pointer to scheduler data. 1 sched per partition */ + struct panthor_arbitration_sched *sched[AM_ARB_MAX_PC_COUNT]; }; +int panthor_arbitration_on_grant (struct panthor_arbitration *adev,u8 sched_id,u8 aw_id); +int panthor_arbitration_on_stop (struct panthor_arbitration *adev,u8 sched_id); +int panthor_arbitration_on_close (struct panthor_arbitration *adev,u8 sched_id); +#endif
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +31 -0
@@ -11,6 +11,7 @@#include <linux/of.h> #include "panthor_arbitration.h" +#include "panthor_arbitration_sched.h" #include "panthor_partition_control.h" #include "panthor_resource_group.h"
@@ -21,6 +22,10 @@ static int panthor_arbitration_runtime_suspend(struct device *dev)struct panthor_arbitration *adev =dev_get_drvdata (dev);int ret =0 ; + ret =panthor_arbitration_sched_suspend (adev); +if (ret) +return ret; + ret =panthor_resource_group_suspend (adev);if (ret)return ret;
@@ -45,6 +50,26 @@ static int panthor_arbitration_runtime_resume(struct device *dev)if (ret)return ret; + ret =panthor_arbitration_sched_resume (adev); +if (ret) +return ret; + +return 0 ; +} + +/* Arbiter to AW events */ +int panthor_arbitration_on_grant (struct panthor_arbitration *adev,u8 sched_id,u8 aw_id) +{ +return 0 ; +} + +int panthor_arbitration_on_stop (struct panthor_arbitration *adev,u8 sched_id) +{ +return 0 ; +} + +int panthor_arbitration_on_close (struct panthor_arbitration *adev,u8 sched_id) +{return 0 ; }
@@ -71,6 +96,10 @@ static int panthor_arbitration_probe(struct platform_device *pdev)if (ret) goto err_disable_pm; + ret =panthor_arbitration_sched_init (adev); +if (ret) + goto err_term; + ret =panthor_partition_control_init (adev);if (ret) goto err_term;
@@ -94,6 +123,7 @@ static int panthor_arbitration_probe(struct platform_device *pdev)of_platform_depopulate (dev); err_term: +panthor_arbitration_sched_term (adev);panthor_resource_group_term (adev);panthor_partition_control_term (adev);pm_runtime_put_sync_suspend (dev);
@@ -119,6 +149,7 @@ static void panthor_arbitration_remove(struct platform_device *pdev)pm_runtime_disable (adev->dev); +panthor_arbitration_sched_term (adev);panthor_partition_control_term (adev);panthor_resource_group_term (adev);
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +838 -0
838 lines not on this page · raw message
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.h new file +38 -0
@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 or MIT */ +/* Copyright 2026 ARM Limited. All rights reserved. */ + +#ifndef __PANTHOR_ARBITRATION_SCHED_H__ +#define __PANTHOR_ARBITRATION_SCHED_H__ + +#include <linux/types.h> + +struct panthor_arbitration ; +struct panthor_arbitration_sched ; + +enum panthor_arb_sched_disable_reason { +/** @ARB_SCHED_DISABLE_PM: scheduler disabled due to PM suspend */ +ARB_SCHED_DISABLE_PM =0 , + +/** @ARB_SCHED_DISABLE_TERM: scheduler disabled for termination */ +ARB_SCHED_DISABLE_TERM , +}; + +int panthor_arbitration_sched_init (struct panthor_arbitration *adev); +void panthor_arbitration_sched_term (struct panthor_arbitration *adev); + +int panthor_arbitration_sched_suspend (struct panthor_arbitration *adev); +int panthor_arbitration_sched_resume (struct panthor_arbitration *adev); + +int panthor_arbitration_sched_stop (struct panthor_arbitration_sched *sched); +int panthor_arbitration_sched_start (struct panthor_arbitration_sched *sched); + +void panthor_arbitration_sched_disable_set (struct panthor_arbitration_sched *sched, +enum panthor_arb_sched_disable_reason reason); +void panthor_arbitration_sched_disable_clear (struct panthor_arbitration_sched *sched, +enum panthor_arb_sched_disable_reason reason); + +int panthor_arbitration_sched_on_request (struct panthor_arbitration_sched *sched,u8 aw_id); +int panthor_arbitration_sched_on_idle (struct panthor_arbitration_sched *sched,u8 aw_id); +int panthor_arbitration_sched_on_stopped (struct panthor_arbitration_sched *sched,u8 aw_id); + +#endif
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 17/28] drm/panthor: Add arbitration scheduler
Thank you for your contribution! Sashiko AI review found 4 potential issues to consider: - [High] drm/panthor: infinite reset loop in arb_sched_reset_work() on close failure - [High] drm/panthor…
Thank you for your contribution! Sashiko AI review found 4 potential issues to consider:
- [High] drm/panthor: infinite reset loop in arb_sched_reset_work() on close failure
- [High] drm/panthor: dropped GPU request in panthor_arbitration_sched_on_request()
- [Medium] drm/panthor: unbounded retry loop in arb_sched_retry_work() on -EAGAIN
- [Medium] drm/panthor: timer re-armed by flush_workqueue() during scheduler stop
--
commit 3de6cc524258ad93c9b3ccfc5bc67b23efebd6b2
Author: Karunika Choo <[email protected]>
drm/panthor: Add arbitration scheduler
This commit adds a per-partition arbitration scheduler that queues GPU requests from access windows, grants access in turn, and uses hrtimers and workqueues to manage timeslices, yields, force-closes, and error recovery.
Quoted 5 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +0
-0
[ ... ]
Quoted 32 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +32
-0+static int __arb_sched_close_locked (struct panthor_arbitration_sched *sched) +{ +int ret; + +lockdep_assert_held (&sched->lock); + + ret =panthor_arbitration_on_close (to_adev (sched), sched->id); +if (ret == -EAGAIN ) { +arb_sched_queue_retry_work (sched,PANTHOR_ARB_WORK_CLOSE ); + }else if (ret <0 ) { +dev_err (sched->dev,"%s: Failed to close AW%u. %d" , sched->name, + sched->active_aw_id, ret); + +arb_sched_queue_work (sched, &sched->reset_work); + } + +return ret; +} + +static void arb_sched_close_locked (struct panthor_arbitration_sched *sched) +{ +int ret; + +lockdep_assert_held (&sched->lock); + + ret =__arb_sched_close_locked (sched); +if (!ret) { + sched->close_timer.epoch = sched->epoch; +hrtimer_start (&sched->close_timer.timer, +ms_to_ktime (yield_timeout),HRTIMER_MODE_REL ); + } +}
[ ... ]
Quoted 8 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +8
-0+static void arb_sched_reset_work (struct work_struct *work) +{ +struct panthor_arbitration_work *w =to_work (work); +struct panthor_arbitration_sched *sched = + container_of(w, struct panthor_arbitration_sched, reset_work); + +guard (spinlock_irqsave)(&sched->lock); +if (sched->epoch != w->epoch)
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c line 414
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +10
-0+return ; + +if (sched->active_aw_id != w->aw_id) +return ; + +dev_warn (sched->dev,"%s: scheduler reset. active_aw=%u" , + sched->name, sched->active_aw_id); + +arb_sched_force_close_locked (sched); +}
[Severity: High]
Can arb_sched_reset_work() enter an infinite reset loop when closing an access window fails or times out?
__arb_sched_close_locked() and panthor_arbitration_sched_on_close_timeout() queue sched->reset_work to recover from close errors and close timeouts. However, arb_sched_reset_work() does not retire the lease or advance sched->epoch (note that arb_sched_on_stopped_locked() has an unused forward declaration at the top of the file); it only calls arb_sched_force_close_locked() -> arb_sched_close_locked().
If panthor_arbitration_on_close() returns a negative error other than -EAGAIN, __arb_sched_close_locked() immediately re-queues sched->reset_work in a tight loop on sched->wq, hanging flush_workqueue() during suspend or teardown. If panthor_arbitration_on_close() returns 0 when close_timer has already timed out, arb_sched_close_locked() simply re-arms close_timer, which expires and queues sched->reset_work again, wedging the scheduler in ARB_SCHED_PHASE_LOST and starving all queued access windows.
Quoted 21 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +21
-0+static void arb_sched_retry_work (struct work_struct *work) +{ +struct panthor_arbitration_work *w =to_work (work); +struct panthor_arbitration_sched *sched = + container_of(w, struct panthor_arbitration_sched, retry_work); +DECLARE_BITMAP (work_tmp,PANTHOR_ARB_WORK_COUNT ); + +guard (spinlock_irqsave)(&sched->lock); +if (bitmap_empty (sched->pending_retry_work,PANTHOR_ARB_WORK_COUNT )) +return ; + +bitmap_copy (work_tmp, sched->pending_retry_work,PANTHOR_ARB_WORK_COUNT ); +bitmap_zero (sched->pending_retry_work,PANTHOR_ARB_WORK_COUNT ); + +if (sched->epoch != w->epoch || sched->active_aw_id != w->aw_id) +return ; + +switch (sched->phase) { +case ARB_SCHED_PHASE_STOPPING : +if (test_bit (PANTHOR_ARB_WORK_STOP , work_tmp)) +arb_sched_stop_locked (sched);
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c line 446
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +10
-0+break ; +case ARB_SCHED_PHASE_CLOSING : +case ARB_SCHED_PHASE_LOST : +if (test_bit (PANTHOR_ARB_WORK_CLOSE , work_tmp)) +arb_sched_close_locked (sched); +break ; +default : +break ; + } +}
[Severity: Medium]
Can arb_sched_retry_work() spin indefinitely on sched->wq if panthor_arbitration_on_stop() or panthor_arbitration_on_close() continues to return -EAGAIN?
When __arb_sched_stop_locked() or __arb_sched_close_locked() gets -EAGAIN, stop_timer and close_timer are not started, and sched->retry_work is queued immediately with no delay or retry limit. If the partition remains in a state that returns -EAGAIN, arb_sched_retry_work() clears pending_retry_work and re-queues itself in an unthrottled busy loop with no running timer to force recovery, which also prevents flush_workqueue(sched->wq) from completing in panthor_arbitration_sched_stop().
[ ... ]
Quoted 4 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +4
-0+int panthor_arbitration_sched_on_request (struct panthor_arbitration_sched *sched,u8 aw_id) +{ +guard (spinlock_irqsave)(&sched->lock); +
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c line 536
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +10
-0+if (aw_id >=AM_ARB_MAX_AW_COUNT ) +return -EINVAL ; + +if (test_bit (aw_id, sched->queued_mask) || + (sched->active_aw_id == aw_id && + sched->phase !=ARB_SCHED_PHASE_STOPPING )) { +dev_warn (sched->dev,"%s: AW%u already in request queue." , + sched->name, aw_id); +return -EEXIST ; + }
[Severity: High]
Does panthor_arbitration_sched_on_request() drop valid GPU requests that arrive while the active access window is closing?
When the active access window yields via panthor_arbitration_sched_on_idle() (or is force-closed), sched->phase moves to ARB_SCHED_PHASE_CLOSING (or ARB_SCHED_PHASE_LOST) while sched->active_aw_id remains set until the partition reset completes and calls panthor_arbitration_sched_on_stopped(). Because the duplicate check only exempts ARB_SCHED_PHASE_STOPPING, a new request from that access window during ARB_SCHED_PHASE_CLOSING or ARB_SCHED_PHASE_LOST is rejected with -EEXIST and never queued, leaving the access window unscheduled once panthor_arbitration_sched_on_stopped() clears active_aw_id.
[ ... ]
Quoted 19 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +19
-0+int panthor_arbitration_sched_stop (struct panthor_arbitration_sched *sched) +{ +int ret; + +arb_sched_request_stop (sched); + +/* +* Provisionally waiting for up to 2x yield_timeout, but path may +* include time taken for panthor_arbitration_on_grant() to complete +* if sched_request_stop() is called while in the GRANTING state. +* +* Realistically, if granting takes more than yield_timeout, HW is in +* bad state either way. Best continue and stop the scheduler. +*/ + ret =arb_sched_wait_phase (sched,ARB_SCHED_PHASE_IDLE , +panthor_arbitration_stop_timeout (sched)); +if (ret) { +/* +* TODO: handle the timeout here by escalating the error when
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c line 810
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c new file +10
-0+* reset escalation is supported. +*/ + ret =arb_sched_force_close (sched); + } + +/* Should no longer have any further activity. Cancel timer. */ +hrtimer_cancel (&sched->grant_timer.timer); +hrtimer_cancel (&sched->stop_timer.timer); +hrtimer_cancel (&sched->close_timer.timer); +flush_workqueue (sched->wq);
[Severity: Medium]
Can flush_workqueue(sched->wq) re-arm stop_timer or close_timer after the timers have already been cancelled?
hrtimer_cancel() runs before flush_workqueue(sched->wq). If sched->reset_work or sched->retry_work is pending (for example, queued by panthor_arbitration_sched_on_close_timeout() during arb_sched_force_close()), flushing sched->wq runs arb_sched_reset_work() or arb_sched_retry_work(), which calls arb_sched_close_locked() or arb_sched_stop_locked() and starts close_timer or stop_timer again, leaving an active hrtimer after panthor_arbitration_sched_stop() returns.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=17
kernel test robot
build botRe: [PATCH v2 17/28] drm/panthor: Add arbitration scheduler
In reply to Karunika Chookernel test robot noticed the following build errors:
Hi Karunika,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-misc/drm-misc-next]
[also build test ERROR on drm/drm-next drm-tip/drm-tip]
[cannot apply to linux-review/Karunika-Choo/drm-panthor-Ignore-EOPNOTSUPP-for-shader-present-nvmem-lookup/20260922-214455 daeinki-drm-exynos/exynos-drm-next drm-i915/for-linux-next drm-i915/for-linux-next-fixes linus/master v7.4-rc2 next-20261109] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Karunika-Choo/drm-panthor-Ignore-EOPNOTSUPP-for-shader-present-nvmem-lookup/20261110-153822 base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next patch link: https://lore.kernel.org/r/20261110153907.3241978-18-karunika.choo%40arm.com patch subject: [PATCH v2 17/28] drm/panthor: Add arbitration scheduler config: um-randconfig-1001-20261111 (https://download.01.org/0day-ci/archive/20261111/[email protected]/config) compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261111/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:223:3: error: call to undeclared function 'hrtimer_start'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
223 | hrtimer_start(&sched->stop_timer.timer,
| ^
>> drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:224:38: error: use of undeclared identifier 'HRTIMER_MODE_REL'
224 | ms_to_ktime(yield_timeout), HRTIMER_MODE_REL);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:249:4: error: call to undeclared function 'hrtimer_start'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
249 | hrtimer_start(&sched->grant_timer.timer,
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:251:11: error: use of undeclared identifier 'HRTIMER_MODE_REL'
251 | HRTIMER_MODE_REL);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:291:3: error: call to undeclared function 'hrtimer_start'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
291 | hrtimer_start(&sched->close_timer.timer,
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:292:38: error: use of undeclared identifier 'HRTIMER_MODE_REL'
292 | ms_to_ktime(yield_timeout), HRTIMER_MODE_REL);
| ^
>> drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:458:6: error: call to undeclared function 'hrtimer_is_queued'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
458 | if (hrtimer_is_queued(timer))
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:483:6: error: call to undeclared function 'hrtimer_is_queued'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
483 | if (hrtimer_is_queued(timer))
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:504:6: error: call to undeclared function 'hrtimer_is_queued'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
504 | if (hrtimer_is_queued(timer))
| ^
>> drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:621:2: error: call to undeclared function 'hrtimer_cancel'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
621 | hrtimer_cancel(&sched->grant_timer.timer);
| ^
>> drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:666:2: error: call to undeclared function 'hrtimer_setup'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
666 | hrtimer_setup(&sched->grant_timer.timer,
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:668:26: error: use of undeclared identifier 'HRTIMER_MODE_REL'
668 | CLOCK_MONOTONIC, HRTIMER_MODE_REL);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:671:26: error: use of undeclared identifier 'HRTIMER_MODE_REL'
671 | CLOCK_MONOTONIC, HRTIMER_MODE_REL);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:674:26: error: use of undeclared identifier 'HRTIMER_MODE_REL'
674 | CLOCK_MONOTONIC, HRTIMER_MODE_REL);
| ^
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:807:2: error: call to undeclared function 'hrtimer_cancel'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
807 | hrtimer_cancel(&sched->grant_timer.timer);
| ^15 errors generated.
vim +/hrtimer_start +223 drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c
207
208 static void arb_sched_stop_locked(struct panthor_arbitration_sched *sched)
209 {
210 int ret;
211
212 lockdep_assert_held(&sched->lock);
213
214 ret = __arb_sched_stop_locked(sched);
215 if (!ret) {
216 if (sched->phase != ARB_SCHED_PHASE_STOPPING) {
217 dev_warn(sched->dev, "%s: Stop ACKED when not yielding",
218 sched->name);
219 return;
220 }
221
222 sched->stop_timer.epoch = sched->epoch;
> 223 hrtimer_start(&sched->stop_timer.timer, > 224 ms_to_ktime(yield_timeout), HRTIMER_MODE_REL);
225 }
226 }
227
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
PATCH v2 18/28 drm/panthor: Route arbitration events
In reply to Karunika ChooConnect resource-group message handling, the arbitration scheduler and partition control.
Forward GPU request and idle messages to the scheduler. When a partition reset completes after firmware yields GPU access or a CLOSE_WINDOW command, report the active access window as stopped.
Add callbacks that let the scheduler grant GPU access, request a yield and close access windows.
---
v2:
- Align with sched to AW interface changes.
v1:
- Notify arbitration scheduler when RESET_DONE completes due to close_window, as well as due to yield by Panthor FW.
.../panthor/arbitration/panthor_arbitration.h | 6 ++++ .../arbitration/panthor_arbitration_drv.c | 28 +++++++++++++++++-- .../arbitration/panthor_partition_control.c | 9 ++++++ .../arbitration/panthor_resource_group.c | 4 +-- 4 files changed, 42 insertions(+), 5 deletions(-)
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h +6 -0
@@ -34,6 +34,12 @@ struct panthor_arbitration {struct panthor_arbitration_sched *sched[AM_ARB_MAX_PC_COUNT ]; }; +/* AW to Arbiter events */ +int panthor_arbitration_on_request (struct panthor_arbitration *adev,u8 aw_id); +int panthor_arbitration_on_idle (struct panthor_arbitration *adev,u8 aw_id); +int panthor_arbitration_on_stopped (struct panthor_arbitration *adev,u8 aw_id); + +/* Arbiter to AW events */ int panthor_arbitration_on_grant (struct panthor_arbitration *adev,u8 sched_id,u8 aw_id);int panthor_arbitration_on_stop (struct panthor_arbitration *adev,u8 sched_id);int panthor_arbitration_on_close (struct panthor_arbitration *adev,u8 sched_id);
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +25 -3
@@ -57,20 +57,42 @@ static int panthor_arbitration_runtime_resume(struct device *dev)return 0 ; } +/* AW to Arbiter events */ +int panthor_arbitration_on_request (struct panthor_arbitration *adev,u8 aw_id) +{ +/* TODO: AW to PC assignment */ +return panthor_arbitration_sched_on_request (adev->sched[0 ], aw_id); +} + +int panthor_arbitration_on_idle (struct panthor_arbitration *adev,u8 aw_id) +{ +/* TODO: AW to PC assignment */ +return panthor_arbitration_sched_on_idle (adev->sched[0 ], aw_id); +} + +int panthor_arbitration_on_stopped (struct panthor_arbitration *adev,u8 aw_id) +{ +/* TODO: AW to PC assignment */ +return panthor_arbitration_sched_on_stopped (adev->sched[0 ], aw_id); +} +/* Arbiter to AW events */ int panthor_arbitration_on_grant (struct panthor_arbitration *adev,u8 sched_id,u8 aw_id) { -return 0 ; +/* TODO: AW to PC assignment */ +return panthor_partition_control_open_window (adev->pc[0 ], aw_id); }int panthor_arbitration_on_stop (struct panthor_arbitration *adev,u8 sched_id) { -return 0 ; +/* TODO: AW to PC assignment */ +return panthor_partition_control_yield_now (adev->pc[0 ]); }int panthor_arbitration_on_close (struct panthor_arbitration *adev,u8 sched_id) { -return 0 ; +/* TODO: AW to PC assignment */ +return panthor_partition_control_close_window (adev->pc[0 ]); }static int panthor_arbitration_probe (struct platform_device *pdev)
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +9 -0
@@ -198,13 +198,22 @@ static int window_open(struct panthor_partition_control *pc, u8 aw_id)static void partition_handle_reset_done (struct panthor_partition_control *pc) { +bool notify_stopped = false; +int aw_id; + scoped_guard(spinlock_irqsave, &pc->lock) { + aw_id = pc->current_aw; pc->current_aw =AW_UNASSIGNED ;/* RESET_DONE from CLOSE_WINDOW */ if (pc->closing) pc->closing = false; +if (aw_id >=0 ) + notify_stopped = true; } + +if (notify_stopped) +panthor_arbitration_on_stopped (dev_get_drvdata (pc->dev), aw_id); }static irqreturn_t partition_irq_raw_handler (int irq,void *data)
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c +2 -2
@@ -163,10 +163,10 @@ static void rg_handle_message(struct panthor_resource_group *rg, u8 aw_id,switch (msg_id) {case VM_ARB_GPU_REQUEST : -/* TODO: on_request */ +panthor_arbitration_on_request (dev_get_drvdata (rg->dev), aw_id);break ;case VM_ARB_GPU_STOPPED : -/* TODO: on_idle */ +panthor_arbitration_on_idle (dev_get_drvdata (rg->dev), aw_id);break ;default :dev_warn (rg->dev,"Invalid message (0x%llx)" , message);
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 18/28] drm/panthor: Route arbitration events
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [High] drm/panthor: unhandled RESET and current_aw states wedge arbitration - [Medium] drm/panthor: dropped…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [High] drm/panthor: unhandled RESET and current_aw states wedge arbitration
- [Medium] drm/panthor: dropped GPU_REQUEST in panthor_arbitration_sched_on_request()
--
commit 48a85078af75aa6fff27b7d739d44d8c4f545271
Author: Karunika Choo <[email protected]>
drm/panthor: Route arbitration events
This commit wires arbitration events between resource-group message handling, the arbitration scheduler, and partition control.
Quoted 15 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +4
-0@@ -198,13 +198,22 @@ static int window_open(struct panthor_partition_control *pc, u8 aw_id)static void partition_handle_reset_done (struct panthor_partition_control *pc) { +bool notify_stopped = false; +int aw_id; + scoped_guard(spinlock_irqsave, &pc->lock) { + aw_id = pc->current_aw; pc->current_aw =AW_UNASSIGNED ;
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c static int window_open(struct panthor_partition_control *pc, u8 aw_id) · line 217
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +5
-0/* RESET_DONE from CLOSE_WINDOW */ if (pc->closing) pc->closing = false; +if (aw_id >=0 ) + notify_stopped = true; } + +if (notify_stopped) +panthor_arbitration_on_stopped (dev_get_drvdata (pc->dev), aw_id); }
[Severity: High]
Can relying solely on partition_handle_reset_done() with pc->current_aw >= 0 drop partition commands or wedge the arbitration scheduler in an infinite close loop?
First, window_open() performs a posted write of PART_CMD_OPEN_WINDOW, sets pc->current_aw = aw_id, and returns 0 before AM_PART_STATE leaves PART_STATE_RESET. If the scheduler immediately follows up with a stop, yield, or close command (for example when sched->disabled is set in arb_sched_grant_locked(), or when another request is queued), yield_now() and window_close() see partition_state_get(pc) == PART_STATE_RESET and return 0 without issuing a command or returning -EAGAIN:
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:window_close() {
...
if (partition_state_get(pc) == PART_STATE_RESET)
return 0;
if (partition_state_get(pc) != PART_STATE_WINDOW_OPEN)
return -EAGAIN;
...
}Because 0 is returned while pc->current_aw >= 0, the command is silently dropped instead of being retried once the window finishes opening.
Second, if partition_state_get(pc) is already PART_STATE_WINDOW_OPEN on entry to window_open(), it returns 0 (when cur_aw == aw_id) or -EBUSY (which triggers reset_work -> arb_sched_force_close_locked()) before setting pc->current_aw = aw_id. When PART_RESET_DONE later fires, pc->current_aw is still AW_UNASSIGNED, so partition_handle_reset_done() skips panthor_arbitration_on_stopped().
Third, whenever the hardware partition is already in PART_STATE_RESET while sched->active_aw_id >= 0 (such as after a skipped panthor_arbitration_on_stopped() notification), arb_sched_close_locked() calls window_close(), gets 0 back without any PART_CMD_CLOSE_WINDOW or stopped notification, and starts close_timer. When close_timer expires, reset_work calls arb_sched_force_close_locked() -> arb_sched_close_locked(), repeating indefinitely and wedging GPU scheduling across all access windows.
Quoted 5 lines
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c +0
-0
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c static void rg_handle_message(struct panthor_resource_group *rg, u8 aw_id, · line 170
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_resource_group.c +2
-2@@ -163,10 +163,10 @@ static void rg_handle_message(struct panthor_resource_group *rg, u8 aw_id,switch (msg_id) {case VM_ARB_GPU_REQUEST : -/* TODO: on_request */ +panthor_arbitration_on_request (dev_get_drvdata (rg->dev), aw_id);break ;case VM_ARB_GPU_STOPPED : -/* TODO: on_idle */ +panthor_arbitration_on_idle (dev_get_drvdata (rg->dev), aw_id);break ;
[Severity: Medium]
Can a VM_ARB_GPU_REQUEST sent right after VM_ARB_GPU_STOPPED be rejected with -EEXIST and lost while the partition is still closing?
Receiving VM_ARB_GPU_STOPPED calls panthor_arbitration_sched_on_idle(), which sets sched->phase = ARB_SCHED_PHASE_CLOSING and starts an asynchronous PART_CMD_CLOSE_WINDOW while keeping sched->active_aw_id == aw_id until PART_RESET_DONE fires on the partition control IRQ. Because the access window receives WINDOW_IRQ_WINDOW_CLOSED as soon as the window closes (prior to PART_RESET_DONE) and the resource group and partition control use separate interrupts, the access window can send a new VM_ARB_GPU_REQUEST while sched->phase is still ARB_SCHED_PHASE_CLOSING.
In panthor_arbitration_sched_on_request(), only ARB_SCHED_PHASE_STOPPING is exempted when checking whether the active access window may re-queue itself:
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:panthor_arbitration_sched_on_request() {
...
if (test_bit(aw_id, sched->queued_mask) ||
(sched->active_aw_id == aw_id &&
sched->phase != ARB_SCHED_PHASE_STOPPING)) {
dev_warn(sched->dev, "%s: AW%u already in request queue.",
sched->name, aw_id);
return -EEXIST;
}
...
}The new request is dropped, and once PART_RESET_DONE completes, the scheduler becomes idle without granting the GPU back to the access window, stalling it until its request timeout expires. Allowing re-queuing when sched->phase == ARB_SCHED_PHASE_CLOSING as well would avoid dropping the request.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=18
PATCH v2 19/28 drm/panthor: Add AW assignment tracking
In reply to Karunika ChooTrack the scheduler assigned to each access window. Initialize assignments from the access-window masks in partition child DT nodes.
Use the AW mapping to route request, idle and stopped events to the assigned scheduler. Use the scheduler ID to select the partition for grant, stop and close commands.
Record requests from unassigned access windows and forward them after assignment. Keep schedulers disabled while they have no assigned access windows. Assign all AWs to partition 0 if DT property is not set or is zero.
---
v2:
- Assign AWs to pc0 by default if no arm,access-window-mask is 0 or not set.
- Introduce assignment_lock to protect assignments allowing serialized lookup without the need for READ_ONCE or WRITE_ONCE.
- Add pending_aw_request_mask to track and replay pending requests arriving before AW assignments are initialized.
.../panthor/arbitration/panthor_arbitration.h | 23 ++ .../arbitration/panthor_arbitration_drv.c | 244 +++++++++++++++++- .../arbitration/panthor_arbitration_sched.c | 2 + .../arbitration/panthor_arbitration_sched.h | 3 + 4 files changed, 260 insertions(+), 12 deletions(-)
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h +23 -0
@@ -4,9 +4,11 @@#ifndef __PANTHOR_ARBITRATION_H__#define __PANTHOR_ARBITRATION_H__ +#include <linux/bits.h> #include <linux/ioport.h> #include <linux/fwnode.h> #include <linux/types.h> +#include <linux/spinlock.h> struct device ;struct panthor_arbitration_sched ;
@@ -16,6 +18,12 @@ struct panthor_resource_group;#define AM_ARB_MAX_PC_COUNT 1#define AM_ARB_MAX_RG_COUNT 1#define AM_ARB_MAX_AW_COUNT 16 +#define AM_ARB_MAX_AW_MASK GENMASK(AM_ARB_MAX_AW_COUNT - 1, 0) + +struct panthor_arbitration_dt_info { +/** @default_aw_masks: Default per-partition AW assignments */ +u32 default_aw_masks[AM_ARB_MAX_PC_COUNT ]; +};/** * struct panthor_arbitration - Arbitration device
@@ -32,6 +40,21 @@ struct panthor_arbitration {/** @sched: Pointer to scheduler data. 1 sched per partition */ struct panthor_arbitration_sched *sched[AM_ARB_MAX_PC_COUNT ]; + +/** @dt_info: Properties parsed from the device tree */ +struct panthor_arbitration_dt_info dt_info; + +/** @assignment_lock: Protects assignments */ +spinlock_t assignment_lock; + +/** @aw_sched_map: Tracks assignment of AW to sched instance */ +s8 aw_sched_map[AM_ARB_MAX_AW_COUNT ]; + +/** +* @pending_aw_request_mask: Bitmap of unassigned AWs with pending +* requests +*/ +DECLARE_BITMAP (pending_aw_request_mask,AM_ARB_MAX_AW_COUNT ); };/* AW to Arbiter events */
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +232 -12
305 lines not on this page · raw message
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +2 -0
@@ -662,6 +662,8 @@ static int arbitration_sched_init(struct panthor_arbitration *adev, int i)INIT_KFIFO (sched->queue); sched->active_aw_id =-1 ; sched->phase =ARB_SCHED_PHASE_IDLE ; +/* Scheduler is disabled until its resources are configured */ + sched->disabled =BIT (ARB_SCHED_DISABLE_RESOURCE ); hrtimer_setup(&sched->grant_timer.timer, panthor_arbitration_sched_on_grant_timeout,
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.h +3 -0
@@ -15,6 +15,9 @@ enum panthor_arb_sched_disable_reason {/** @ARB_SCHED_DISABLE_TERM: scheduler disabled for termination */ ARB_SCHED_DISABLE_TERM , + +/** @ARB_SCHED_DISABLE_RESOURCE: No resource assigned. scheduler disabled. */ + ARB_SCHED_DISABLE_RESOURCE, };int panthor_arbitration_sched_init (struct panthor_arbitration *adev);
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 19/28] drm/panthor: Add AW assignment tracking
Thank you for your contribution! Sashiko AI review found 3 potential issues to consider: - [Medium] drm/panthor: race replaying pending AW requests in arbitration_resource_init() - [Low]…
Thank you for your contribution! Sashiko AI review found 3 potential issues to consider:
- [Medium] drm/panthor: race replaying pending AW requests in arbitration_resource_init()
- [Low] drm/panthor: remove extraneous semicolon after to_assigned_sched_idx()
- [Low] drm/panthor: initialize __free() variable in arbitration_dt_parse_assigned_aw()
--
commit e073b116d1f4f953a3ab51f1f483486ff4942f9f
Author: Karunika Choo <[email protected]>
drm/panthor: Add AW assignment tracking
This commit tracks the scheduler assigned to each access window, initializes assignments from device tree partition masks, and replays requests that arrive before access windows are assigned.
Quoted 4 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +0
-0
[ ... ]
Quoted 15 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +11
-0@@ -17,6 +19,28 @@#define PANTHOR_PM_AUTOSUSPEND_DELAY_MS 100 +#define DT_ASSIGNED_AW "arm,access-window-mask" + +static int to_assigned_sched_idx (struct panthor_arbitration *adev,u8 aw_id) +{ +int idx =-1 ; + +lockdep_assert_held (&adev->assignment_lock); + +if (aw_id >=AM_ARB_MAX_AW_COUNT ) { +dev_err (adev->dev,"Invalid AW ID (%u)" , aw_id); +return -EINVAL ;
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c line 42
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +10
-0+ } + + idx = adev->aw_sched_map[aw_id]; +if (idx <0 || idx >=AM_ARB_MAX_PC_COUNT || !adev->sched[idx]) { +dev_warn_ratelimited (adev->dev,"AW%u not assigned to any sched" , aw_id); +return -ENOENT ; + } + +return idx; +};
[Severity: Low]
This isn't a bug, but there is an extra semicolon after the closing brace of to_assigned_sched_idx().
Quoted 19 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +15
-0@@ -57,42 +81,226 @@ static int panthor_arbitration_runtime_resume(struct device *dev)return 0 ; } +static u32 arbitration_get_sched_aw_mask (struct panthor_arbitration *adev, +u8 sched_id) +{ +u32 aw_mask =0 ; + +lockdep_assert_held (&adev->assignment_lock); + +for (int i =0 ; i <AM_ARB_MAX_AW_COUNT ; i++) { +if (adev->aw_sched_map[i] == sched_id) + aw_mask |=BIT (i); + } + +return aw_mask; +} +
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c static int panthor_arbitration_runtime_resume(struct device *dev) · line 108
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +10
-0+static int arbitration_dt_parse_assigned_aw (struct panthor_arbitration *adev) +{ +struct panthor_arbitration_dt_info *dt_info = &adev->dt_info; +struct device *dev = adev->dev; + struct fwnode_handle *partitions __free(fwnode_handle) = NULL; +u32 seen_mask =0 ; +u8 seen_partitions =0 ; +int ret; + + partitions =device_get_named_child_node (dev,"partitions" );
[Severity: Low]
This isn't a bug, but per the Cleanup API conventions, partitions can be defined and initialized in a single statement rather than initialized to NULL and assigned separately.
[ ... ]
Quoted 62 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +57
-2+static void arbitration_retry_pending_requests (struct panthor_arbitration *adev,u32 mask) +{ +unsigned long aw_mask = mask; +u8 aw_id; + +for_each_set_bit (aw_id, &aw_mask,AM_ARB_MAX_AW_COUNT ) { +int ret; + +if (!test_and_clear_bit (aw_id, adev->pending_aw_request_mask)) +continue ; + + ret =panthor_arbitration_on_request (adev, aw_id); +if (ret && ret != -EEXIST ) +set_bit (aw_id, adev->pending_aw_request_mask); + } +} + +static int arbitration_resource_init (struct panthor_arbitration *adev) +{ +struct panthor_arbitration_dt_info *dt_info = &adev->dt_info; + +/* +* If arm,access-window-mask is not defined or set to 0, assign AWs to +* PC0 by default. +*/ +if (!dt_info->default_aw_masks[0 ]) + dt_info->default_aw_masks[0 ] =AM_ARB_MAX_AW_MASK ; + +for (int i =0 ; i <AM_ARB_MAX_PC_COUNT ; i++) { +unsigned long pc_aw_mask = dt_info->default_aw_masks[i]; +u8 aw_id; +int ret; + +if (!adev->pc[i] || !adev->sched[i]) +continue ; + + scoped_guard(spinlock_irqsave, &adev->assignment_lock) { +for_each_set_bit (aw_id, &pc_aw_mask,AM_ARB_MAX_AW_COUNT ) + adev->aw_sched_map[aw_id] = i; + } + + ret =arbitration_sched_try_start (adev, i); +if (ret) +return ret; + } + +arbitration_retry_pending_requests (adev,AM_ARB_MAX_AW_MASK ); + +return 0 ; +} +/* AW to Arbiter events */ int panthor_arbitration_on_request (struct panthor_arbitration *adev,u8 aw_id) { -/* TODO: AW to PC assignment */ -return panthor_arbitration_sched_on_request (adev->sched[0 ], aw_id); +int idx; + +guard (spinlock_irqsave)(&adev->assignment_lock); + + idx =to_assigned_sched_idx (adev, aw_id); +
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c static int panthor_arbitration_runtime_resume(struct device *dev) · line 260
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +9
-0+if (idx == -ENOENT ) { +set_bit (aw_id, adev->pending_aw_request_mask); + +return 0 ; + }else if (idx <0 ) { +return idx; + } + +return panthor_arbitration_sched_on_request (adev->sched[idx], aw_id); }
[Severity: Medium]
Can a request interrupt arriving between publishing adev->aw_sched_map[] and arbitration_retry_pending_requests() reorder or duplicate AW requests?
panthor_resource_group_init() enables Resource Group interrupts and starts the AW handshake before arbitration_resource_init() runs. If an AW sends VM_ARB_GPU_REQUEST before adev->aw_sched_map[] is populated, panthor_arbitration_on_request() sets its bit in pending_aw_request_mask. arbitration_resource_init() then populates adev->aw_sched_map[], drops assignment_lock, and starts the scheduler before draining pending_aw_request_mask:
CPU0 <hardirq>arbitration_resource_init()
rg_irq_handler()
...
panthor_arbitration_on_request(aw0)
set_bit(0, pending_aw_request_mask)
lock(&adev->assignment_lock)
adev->aw_sched_map[aw_id] = i
unlock(&adev->assignment_lock)
arbitration_sched_try_start()
rg_irq_handler()
...
panthor_arbitration_on_request(aw0)
panthor_arbitration_sched_on_request() arbitration_retry_pending_requests()
test_and_clear_bit(0, ...) panthor_arbitration_on_request(aw0)
panthor_arbitration_sched_on_request() <-- duplicate replay
Because panthor_arbitration_on_request() does not clear aw_id in pending_aw_request_mask when idx >= 0, a resent request (such as from panthor_aw_handshake_handle() on ARB_VM_INIT) is queued once by the interrupt handler and replayed a second time by arbitration_retry_pending_requests(), triggering a spurious warning in panthor_arbitration_sched_on_request() or an extra GPU grant if the AW has already entered ARB_SCHED_PHASE_STOPPING or ARB_SCHED_PHASE_IDLE. A request from a different AW in that window also bypasses the earlier pending request and is granted the GPU first.
Replaying pending requests under assignment_lock when populating adev->aw_sched_map[] (before starting the scheduler), or clearing pending_aw_request_mask in panthor_arbitration_on_request(), would avoid the race.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=19
PATCH v2 20/28 drm/panthor: Handle partition control INVALID_COMMAND interrupt
In reply to Karunika ChooPartition commands can be rejected while the hardware changes state.
Track the latest command and its target access window. Handle INVALID_COMMAND interrupts without waiting for state transitions in IRQ context.
Retry yield and close commands unless the partition is in RESET. Retry open commands unless the partition is in WINDOW_OPEN.
If an open command finds the partition open for a different access window, request scheduler recovery.
Handle INVALID_COMMAND before RESET_DONE. Clear the saved command when handling RESET_DONE.
---
v2:
- make error notification hold assignment_lock during sched_id lookup.
- Track YIELD_IDLE and update invalid command handling to prevent untracked commands from triggering the interrupt for valid commands that pass.
- Move invalid command handling before RESET_DONE.
.../panthor/arbitration/panthor_arbitration.h | 2 + .../arbitration/panthor_arbitration_drv.c | 16 +++ .../arbitration/panthor_arbitration_sched.c | 10 ++ .../arbitration/panthor_arbitration_sched.h | 4 + .../arbitration/panthor_partition_control.c | 109 +++++++++++++++--- 5 files changed, 128 insertions(+), 13 deletions(-)
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h +2 -0
@@ -67,4 +67,6 @@ int panthor_arbitration_on_grant(struct panthor_arbitration *adev, u8 sched_id,int panthor_arbitration_on_stop (struct panthor_arbitration *adev,u8 sched_id);int panthor_arbitration_on_close (struct panthor_arbitration *adev,u8 sched_id); +int panthor_arbitration_notify_err (struct panthor_arbitration *adev,u8 aw_id); +#endif
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +16 -0
@@ -303,6 +303,22 @@ int panthor_arbitration_on_close(struct panthor_arbitration *adev, u8 sched_id)return panthor_partition_control_close_window (adev->pc[sched_id]); } +int panthor_arbitration_notify_err (struct panthor_arbitration *adev,u8 aw_id) +{ +int idx; + +guard (spinlock_irqsave)(&adev->assignment_lock); + + idx =to_assigned_sched_idx (adev, aw_id); + +if (idx <0 ) +return idx; + +panthor_arbitration_sched_reset (adev->sched[idx], aw_id); + +return 0 ; +} +static int panthor_arbitration_probe (struct platform_device *pdev) {struct panthor_arbitration *adev;
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +10 -0
@@ -838,3 +838,13 @@ void panthor_arbitration_sched_disable_clear(struct panthor_arbitration_sched *s sched->disabled &= ~BIT (reason); } + +void panthor_arbitration_sched_reset (struct panthor_arbitration_sched *sched,u8 aw_id) +{ +guard (spinlock_irqsave)(&sched->lock); + +if (aw_id != sched->active_aw_id) +return ; + +arb_sched_queue_work (sched, &sched->reset_work); +}
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.h +4 -0
@@ -6,6 +6,8 @@#include <linux/types.h> +#include "panthor_arbitration.h" +struct panthor_arbitration ;struct panthor_arbitration_sched ;
@@ -34,6 +36,8 @@ void panthor_arbitration_sched_disable_set(struct panthor_arbitration_sched *schvoid panthor_arbitration_sched_disable_clear (struct panthor_arbitration_sched *sched,enum panthor_arb_sched_disable_reason reason); +void panthor_arbitration_sched_reset (struct panthor_arbitration_sched *sched,u8 aw_id); +int panthor_arbitration_sched_on_request (struct panthor_arbitration_sched *sched,u8 aw_id);int panthor_arbitration_sched_on_idle (struct panthor_arbitration_sched *sched,u8 aw_id);int panthor_arbitration_sched_on_stopped (struct panthor_arbitration_sched *sched,u8 aw_id);
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +96 -13
181 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 20/28] drm/panthor: Handle partition control INVALID_COMMAND interrupt
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [Medium] drm/panthor: unassigned current_aw in window_open() breaks recovery - [Medium] drm/panthor: stale…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [Medium] drm/panthor: unassigned current_aw in window_open() breaks recovery
- [Medium] drm/panthor: stale last_cmd on PART_STATE_RESET in yield/close helpers
--
commit 94f33b60c028012f4fc4c4edbb429977e08e2557
Author: Karunika Choo <[email protected]>
drm/panthor: Handle partition control INVALID_COMMAND interrupt
This commit tracks the last sent partition command and handles PART_INVALID_COMMAND interrupts by retrying rejected commands or requesting scheduler recovery when the partition is open for a different access window.
Quoted 4 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +0
-0
[ ... ]
Quoted 23 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +4
-4@@ -128,8 +158,8 @@ static int yield_now(struct panthor_partition_control *pc)if (partition_state_get (pc) !=PART_STATE_WINDOW_OPEN )return -EAGAIN ; -gpu_write (pc->iomem,AM_PART_COMMAND , -AM_PART_SET_COMMAND (PART_CMD_YIELD_NOW )); +partition_command_write (pc,AM_PART_SET_COMMAND (PART_CMD_YIELD_NOW ), + pc->current_aw);return 0 ; }@@ -144,8 +174,8 @@ static int yield_idle(struct panthor_partition_control *pc)if (partition_state_get (pc) !=PART_STATE_WINDOW_OPEN )return -EAGAIN ; -gpu_write (pc->iomem,AM_PART_COMMAND , -AM_PART_SET_COMMAND (PART_CMD_YIELD_IDLE )); +partition_command_write (pc,AM_PART_SET_COMMAND (PART_CMD_YIELD_IDLE ), + pc->current_aw);return 0 ; }
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c static int window_close(struct panthor_partition_control *pc) · line 199
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +2
-2@@ -162,8 +192,8 @@ static int window_close(struct panthor_partition_control *pc) pc->closing = true; -gpu_write (pc->iomem,AM_PART_COMMAND , -AM_PART_SET_COMMAND (PART_CMD_CLOSE_WINDOW )); +partition_command_write (pc,AM_PART_SET_COMMAND (PART_CMD_CLOSE_WINDOW ), + pc->current_aw);return 0 ; }
[Severity: Medium]
Can a stale PART_CMD_OPEN_WINDOW in pc->last_cmd reopen the partition after yield_now(), yield_idle(), or window_close() has already returned 0?
window_open() writes PART_CMD_OPEN_WINDOW, stores it in pc->last_cmd, and returns 0 without waiting for AM_PART_STATE to leave PART_STATE_RESET. If PART_CMD_OPEN_WINDOW is rejected while a previous reset is still finishing (or before the hardware leaves PART_STATE_RESET) and the scheduler then calls yield_now(), yield_idle(), or window_close(), those helpers see partition_state_get(pc) == PART_STATE_RESET and return 0 without clearing pc->last_cmd or scheduling retry_work:
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:yield_now() {
guard(spinlock_irqsave)(&pc->lock);
if (partition_state_get(pc) == PART_STATE_RESET)
return 0;When partition_handle_invalid_cmd() later runs for the rejected open command, pc->last_cmd.cmd is still PART_CMD_OPEN_WINDOW and the partition is not in PART_STATE_WINDOW_OPEN, so it re-issues PART_CMD_OPEN_WINDOW and opens the access window after the yield or close already succeeded.
Quoted 35 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +11
-2@@ -188,8 +218,8 @@ static int window_open(struct panthor_partition_control *pc, u8 aw_id)return -EBUSY ; } -gpu_write (pc->iomem,AM_PART_COMMAND , -AM_PART_SET_COMMAND (PART_CMD_OPEN_WINDOW ) |AM_PART_SET_WINDOW (aw_id)); +partition_command_write (pc, (AM_PART_SET_COMMAND (PART_CMD_OPEN_WINDOW ) | +AM_PART_SET_WINDOW (aw_id)), aw_id); pc->current_aw = aw_id;@@ -201,10 +231,16 @@ static void partition_handle_reset_done(struct panthor_partition_control *pc)bool notify_stopped = false;int aw_id; +gpu_write (pc->iomem,AM_PART_IRQ_CLEAR ,PART_RESET_DONE ); + scoped_guard(spinlock_irqsave, &pc->lock) { aw_id = pc->current_aw; pc->current_aw =AW_UNASSIGNED ; +/* invalidate last command */ + pc->last_cmd.aw_id =AW_UNASSIGNED ; + pc->last_cmd.cmd =0 ; +/* RESET_DONE from CLOSE_WINDOW */ if (pc->closing) pc->closing = false;@@ -216,6 +252,55 @@ static void partition_handle_reset_done(struct panthor_partition_control *pc)panthor_arbitration_on_stopped (dev_get_drvdata (pc->dev), aw_id); } +static void partition_handle_invalid_cmd (struct panthor_partition_control *pc) +{ +bool on_err = false;
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c static void partition_handle_reset_done(struct panthor_partition_control *pc) · line 267
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +10
-0+int aw_id; + +gpu_write (pc->iomem,AM_PART_IRQ_CLEAR ,PART_INVALID_COMMAND ); + + scoped_guard(spinlock_irqsave, &pc->lock) { +if (!pc->last_cmd.cmd) +return ; + +if (pc->last_cmd.aw_id <0 ) +return ;
[Severity: Medium]
Does leaving pc->current_aw as AW_UNASSIGNED (-1) when window_open() finds the partition in PART_STATE_WINDOW_OPEN prevent command retries and scheduler recovery?
When window_open() sees PART_STATE_WINDOW_OPEN, it returns 0 (if cur_aw == aw_id) or -EBUSY (if cur_aw != aw_id) before setting pc->current_aw = aw_id:
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:window_open() {
if (partition_state_get(pc) == PART_STATE_WINDOW_OPEN) {
u8 cur_aw = partition_aw_get(pc);
if (cur_aw == aw_id)
return 0;
dev_warn(pc->dev,
"%s: OPEN_WINDOW(%u): Already opened for aw=%u, state=%u. Closing...",
pc->name, aw_id, cur_aw, partition_state_get(pc));
return -EBUSY;
}On -EBUSY, arb_sched_grant_locked() queues sched->reset_work, which calls arb_sched_force_close_locked() -> arb_sched_close_locked() -> window_close(). Because pc->current_aw is still -1, window_close() (as well as yield_now() and yield_idle() when cur_aw == aw_id) records pc->last_cmd.aw_id = -1. If that command raises PART_INVALID_COMMAND, partition_handle_invalid_cmd() aborts at pc->last_cmd.aw_id < 0 without retrying it. Furthermore, when PART_RESET_DONE later fires, partition_handle_reset_done() sees aw_id < 0 and skips panthor_arbitration_on_stopped(), leaving the scheduler stuck in ARB_SCHED_PHASE_LOST.
In addition, panthor_partition_control_term() calls partition_irq_suspend() before window_close() and partition_state_wait(), which masks PART_INVALID_COMMAND so a rejected close command cannot be retried during teardown.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=20
PATCH v2 21/28 drm/panthor: Request AW to yield GPU access on idle
In reply to Karunika Choov15 GPU introduces a YIELD_IDLE command/interrupt to signal an access window to relinquish GPU access as soon as it is idle. With FW v2, the GPU is immediately yielded when it detects the GPU is idle and the YIELD_IDLE interrupt is raised.
For latency and CPU scheduling reasons, we want to avoid constantly yielding the GPU the moment it goes idle when there is only a singular access window requesting access. As such, we only send YIELD_IDLE when:
- The GPU is granted to an access window and there are other access windows requesting GPU access.
- A new GPU_REQUEST was received and the currently active access window was the singular requesting AW.
---
v2:
- Align with arbitration scheduler retry work changes
- Align with sched-to-AW interface changes.
.../panthor/arbitration/panthor_arbitration.h | 1 + .../arbitration/panthor_arbitration_drv.c | 5 +++ .../arbitration/panthor_arbitration_sched.c | 34 ++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-)
drivers/gpu/drm/panthor/arbitration/panthor_arbitration.h +1 -0
@@ -67,6 +67,7 @@ int panthor_arbitration_on_grant(struct panthor_arbitration *adev, u8 sched_id,int panthor_arbitration_on_stop (struct panthor_arbitration *adev,u8 sched_id);int panthor_arbitration_on_close (struct panthor_arbitration *adev,u8 sched_id); +int panthor_arbitration_notify_yield_idle (struct panthor_arbitration *adev,u8 sched_id);int panthor_arbitration_notify_err (struct panthor_arbitration *adev,u8 aw_id);#endif
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_drv.c +5 -0
@@ -303,6 +303,11 @@ int panthor_arbitration_on_close(struct panthor_arbitration *adev, u8 sched_id)return panthor_partition_control_close_window (adev->pc[sched_id]); } +int panthor_arbitration_notify_yield_idle (struct panthor_arbitration *adev,u8 sched_id) +{ +return panthor_partition_control_yield_idle (adev->pc[sched_id]); +} +int panthor_arbitration_notify_err (struct panthor_arbitration *adev,u8 aw_id) {int idx;
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +33 -1
@@ -53,6 +53,7 @@ struct panthor_arbitration_work {enum panthor_arbitration_retry_work {PANTHOR_ARB_WORK_STOP =0 ,PANTHOR_ARB_WORK_CLOSE , +PANTHOR_ARB_WORK_YIELD_IDLE ,PANTHOR_ARB_WORK_COUNT , };
@@ -186,6 +187,17 @@ static void arb_sched_queue_retry_work(struct panthor_arbitration_sched *sched,arb_sched_queue_work (sched, &sched->retry_work); } +static void arb_sched_yield_idle_locked (struct panthor_arbitration_sched *sched) +{ +int ret; + +lockdep_assert_held (&sched->lock); + + ret =panthor_arbitration_notify_yield_idle (to_adev (sched), sched->id); +if (ret == -EAGAIN ) +arb_sched_queue_retry_work (sched,PANTHOR_ARB_WORK_YIELD_IDLE ); +} +static int __arb_sched_stop_locked (struct panthor_arbitration_sched *sched) {int ret;
@@ -382,6 +394,10 @@ static int arb_sched_next_locked(struct panthor_arbitration_sched *sched)arb_sched_grant_locked (sched); +if (sched->phase ==ARB_SCHED_PHASE_GRANTED && + !kfifo_is_empty (&sched->queue)) +arb_sched_yield_idle_locked (sched); +wake_up_all (&sched->waitqueue);return 0 ;
@@ -431,6 +447,12 @@ static void arb_sched_retry_work(struct work_struct *work)return ;switch (sched->phase) { +case ARB_SCHED_PHASE_IDLE : +case ARB_SCHED_PHASE_GRANTING : +case ARB_SCHED_PHASE_GRANTED : +if (test_bit (PANTHOR_ARB_WORK_YIELD_IDLE , work_tmp)) +arb_sched_yield_idle_locked (sched); +break ;case ARB_SCHED_PHASE_STOPPING :if (test_bit (PANTHOR_ARB_WORK_STOP , work_tmp))arb_sched_stop_locked (sched);
@@ -551,8 +573,18 @@ int panthor_arbitration_sched_on_request(struct panthor_arbitration_sched *sched* Grant timer for the current AW has previously expired, request it to * yield the GPU. */ -if (sched->grant_previously_expired) +if (sched->grant_previously_expired) {arb_sched_request_stop_locked (sched); +return 0 ; + } + +/* +* GPU was previously granted to a lone requesting AW, YIELD_IDLE was +* not sent to it. Send YIELD_IDLE to it now that multiple AWs are +* requesting for the GPU. +*/ +if (sched->phase ==ARB_SCHED_PHASE_GRANTED &&kfifo_len (&sched->queue) ==1 ) +arb_sched_yield_idle_locked (sched);return 0 ; }
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 21/28] drm/panthor: Request AW to yield GPU access on idle
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [Medium] drm/panthor: dropped YIELD_IDLE command in arb_sched_next_locked() - [Medium] drm/panthor: dropped…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [Medium] drm/panthor: dropped YIELD_IDLE command in arb_sched_next_locked()
- [Medium] drm/panthor: dropped GPU_REQUEST in panthor_arbitration_sched_on_request()
--
commit f99f87c6e1d4cdf3c37b5e1e28569f0fc943d72a
Author: Karunika Choo <[email protected]>
drm/panthor: Request AW to yield GPU access on idle
This commit sends a YIELD_IDLE notification to the active access window when other access windows are waiting in the arbitration scheduler queue or when a second access window requests GPU access.
Quoted 4 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +0
-0
[ ... ]
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c static int arb_sched_next_locked(struct panthor_arbitration_sched *sched) · line 403
Quoted 11 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +4
-0@@ -382,6 +394,10 @@ static int arb_sched_next_locked(struct panthor_arbitration_sched *sched)arb_sched_grant_locked (sched); +if (sched->phase ==ARB_SCHED_PHASE_GRANTED && + !kfifo_is_empty (&sched->queue)) +arb_sched_yield_idle_locked (sched); +wake_up_all (&sched->waitqueue);return 0 ;
[Severity: Medium]
Can arb_sched_yield_idle_locked() silently drop the YIELD_IDLE command when called immediately after arb_sched_grant_locked()?
arb_sched_grant_locked() calls window_open(), which writes PART_CMD_OPEN_WINDOW to AM_PART_COMMAND and returns 0 without waiting for AM_PART_STATE to leave PART_STATE_RESET. When arb_sched_yield_idle_locked() then calls yield_idle(), AM_PART_STATE can still read as PART_STATE_RESET:
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c:yield_idle() {
guard(spinlock_irqsave)(&pc->lock);
if (partition_state_get(pc) == PART_STATE_RESET)
return 0;
if (partition_state_get(pc) != PART_STATE_WINDOW_OPEN)
return -EAGAIN;
...
}Because yield_idle() returns 0 instead of -EAGAIN in PART_STATE_RESET, arb_sched_yield_idle_locked() does not queue PANTHOR_ARB_WORK_YIELD_IDLE, and the active access window holds the GPU even while idle until grant_timer expires.
[ ... ]
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +4
-1@@ -551,8 +573,18 @@ int panthor_arbitration_sched_on_request(struct panthor_arbitration_sched *sched* Grant timer for the current AW has previously expired, request it to * yield the GPU. */ -if (sched->grant_previously_expired) +if (sched->grant_previously_expired) {arb_sched_request_stop_locked (sched); +return 0 ; + } +
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c int panthor_arbitration_sched_on_request(struct panthor_arbitration_sched *sched · line 590
Quoted 10 lines
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c +7
-0+/* +* GPU was previously granted to a lone requesting AW, YIELD_IDLE was +* not sent to it. Send YIELD_IDLE to it now that multiple AWs are +* requesting for the GPU. +*/ +if (sched->phase ==ARB_SCHED_PHASE_GRANTED &&kfifo_len (&sched->queue) ==1 ) +arb_sched_yield_idle_locked (sched);return 0 ; }
[Severity: Medium]
Will panthor_arbitration_sched_on_request() drop a new GPU_REQUEST from an access window that just yielded due to YIELD_IDLE?
Unlike arb_sched_request_stop_locked(), which sets sched->phase to ARB_SCHED_PHASE_STOPPING before sending PART_CMD_YIELD_NOW, sending PART_CMD_YIELD_IDLE leaves sched->phase as ARB_SCHED_PHASE_GRANTED. When the active access window yields on idle, it receives WINDOW_IRQ_WINDOW_CLOSED and can issue a new VM_ARB_GPU_REQUEST before the partition control IRQ processes PART_RESET_DONE and calls panthor_arbitration_on_stopped():
drivers/gpu/drm/panthor/arbitration/panthor_arbitration_sched.c:panthor_arbitration_sched_on_request() {
...
if (test_bit(aw_id, sched->queued_mask) ||
(sched->active_aw_id == aw_id &&
sched->phase != ARB_SCHED_PHASE_STOPPING)) {
dev_warn(sched->dev, "%s: AW%u already in request queue.",
sched->name, aw_id);
return -EEXIST;
}
...
}Because sched->active_aw_id is still aw_id and sched->phase is still ARB_SCHED_PHASE_GRANTED, panthor_arbitration_sched_on_request() rejects the request with -EEXIST, leaving the access window to time out in panthor_aw_request().
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=21
PATCH v2 22/28 drm/panthor: Add access-window support
In reply to Karunika ChooAdd the VM-side access-window component for Mali v15 GPUs.
Negotiate the AM message version, request GPU access from the arbiter, and wait for the window-open interrupt. Yield GPU access during suspend.
Keep hardware binding in panthor_hw_init(). Call panthor_hw_info_init() to read GPU information after panthor_aw_init() obtains GPU access.
---
v2:
- Introduce spinlock to protect and serialize state acquisition and updates.
- Make panthor_aw_request recheck states after wait to handle unexpected state transitions and prevent timing out waiting on an invalid state.
- Tighten protocol version checks and reject sending GPU_REQUEST to incompatible arbiter.
- Handle lost GPU_REQUEST message if arbiter was restarted
- Add WINDOW_CLOSED and WINDOW_OPENED handling.
- Fix indentation for IRQ_NONE return in the IRQ raw handler.
- clean up IRQ state during failed initialization and termination.
- Handle yielding of the GPU during termination.
- Split GPU_STOPPED state into YIELDING and SUSPEND_PENDING. Removed old GPU_STOP state as we no longer support the ARB_VM_GPU_STOP message.
v1:
- Adapt AW IRQ handling to the updated IRQ locking/state interfaces and reuse panthor_irq_suspend().
- Handle -ENOSPC from AM message sending when the outgoing FIFO is full.
drivers/gpu/drm/panthor/Makefile | 1 + drivers/gpu/drm/panthor/panthor_aw.c | 498 +++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_aw.h | 42 ++ drivers/gpu/drm/panthor/panthor_device.c | 15 +- drivers/gpu/drm/panthor/panthor_device.h | 4 + drivers/gpu/drm/panthor/panthor_hw.c | 8 +- drivers/gpu/drm/panthor/panthor_hw.h | 2 + 7 files changed, 563 insertions(+), 7 deletions(-) create mode 100644 drivers/gpu/drm/panthor/panthor_aw.c create mode 100644 drivers/gpu/drm/panthor/panthor_aw.h
drivers/gpu/drm/panthor/Makefile +1 -0
@@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 or MIT panthor-y := \ + panthor_aw.o \ panthor_devfreq.o \ panthor_device.o \ panthor_drv.o \
drivers/gpu/drm/panthor/panthor_aw.c new file +498 -0
498 lines not on this page · raw message
drivers/gpu/drm/panthor/panthor_aw.h new file +42 -0
42 lines not on this page · raw message
drivers/gpu/drm/panthor/panthor_device.c +14 -1
@@ -16,6 +16,7 @@#include <drm/drm_managed.h> #include <drm/drm_print.h> +#include "panthor_aw.h" #include "panthor_devfreq.h" #include "panthor_device.h" #include "panthor_fw.h"
@@ -100,6 +101,7 @@ void panthor_device_unplug(struct panthor_device *ptdev)panthor_gem_shrinker_unplug (ptdev);panthor_gpu_unplug (ptdev);panthor_pwr_unplug (ptdev); +panthor_aw_unplug (ptdev);pm_runtime_dont_use_autosuspend (ptdev->base.dev);pm_runtime_put_sync_suspend (ptdev->base.dev);
@@ -259,10 +261,18 @@ int panthor_device_init(struct panthor_device *ptdev)if (ret) goto err_rpm_put; - ret =panthor_pwr_init (ptdev); + ret =panthor_aw_init (ptdev);if (ret) goto err_rpm_put; + ret =panthor_hw_info_init (ptdev); +if (ret) + goto err_unplug_aw; + + ret =panthor_pwr_init (ptdev); +if (ret) + goto err_unplug_aw; + ret =panthor_gpu_init (ptdev);if (ret) goto err_unplug_pwr;
@@ -322,6 +332,9 @@ int panthor_device_init(struct panthor_device *ptdev) err_unplug_pwr:panthor_pwr_unplug (ptdev); +err_unplug_aw: +panthor_aw_unplug (ptdev); + err_rpm_put:pm_runtime_put_sync_suspend (ptdev->base.dev);return ret;
drivers/gpu/drm/panthor/panthor_device.h +4 -0
@@ -21,6 +21,7 @@#include "panthor_device_io.h" +struct panthor_aw ;struct panthor_csf ;struct panthor_csf_ctx ;struct panthor_device ;
@@ -202,6 +203,9 @@ struct panthor_device {/** @hw: GPU-specific data. */ struct panthor_hw *hw; +/** @aw: AW-specific data */ +struct panthor_aw *aw; +/** @pwr: Power control management data. */ struct panthor_pwr *pwr;
drivers/gpu/drm/panthor/panthor_hw.c +2 -6
@@ -353,7 +353,7 @@ static int panthor_gpu_info_init(struct panthor_device *ptdev)return overload_shader_present (ptdev); } -static int panthor_hw_info_init (struct panthor_device *ptdev) +int panthor_hw_info_init (struct panthor_device *ptdev) {u64 l2_features;u32 prod_id, major, minor, status;
@@ -471,9 +471,5 @@ int panthor_hw_init(struct panthor_device *ptdev)if (ret)return ret; - ret =panthor_hw_bind_device (ptdev); -if (ret) -return ret; - -return panthor_hw_info_init (ptdev); +return panthor_hw_bind_device (ptdev); }
drivers/gpu/drm/panthor/panthor_hw.h +2 -0
@@ -66,6 +66,8 @@ struct panthor_hw { };int panthor_hw_init (struct panthor_device *ptdev); +int panthor_hw_info_init (struct panthor_device *ptdev); +int panthor_hw_power_status_register (void );void panthor_hw_power_status_unregister (void );
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 22/28] drm/panthor: Add access-window support
Thank you for your contribution! Sashiko AI review found 5 potential issues to consider: - [High] drm/panthor: uncanceled msg_retry_work in panthor_aw_suspend() and resume - [Medium] drm/panthor…
Thank you for your contribution! Sashiko AI review found 5 potential issues to consider:
- [High] drm/panthor: uncanceled msg_retry_work in panthor_aw_suspend() and resume
- [Medium] drm/panthor: zero-delay workqueue busy loop in panthor_aw_msg_retry_work()
- [Medium] drm/panthor: unhandled INIT and GPU_REQUEST states in __panthor_aw_suspend()
- [Medium] drm/panthor: unhandled YIELDING timeout and INIT wait in panthor_aw
- [Low] drm/panthor: unchecked version in panthor_aw_handshake_handle() resend path
--
commit 2a64ca6e72bd954e55857187b10a1459415f36df
Author: Karunika Choo <[email protected]>
drm/panthor: Add access-window support
This commit adds the VM-side access-window component for Mali v15 GPUs to negotiate the AM message protocol, request and yield GPU access from the arbiter, and defer reading hardware information until GPU access is granted.
Quoted 6 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +0
-0@@ -0,0 +1,498 @@
[ ... ]
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +4
-0+static void panthor_aw_msg_retry_work (struct work_struct *work) +{ +struct panthor_aw *aw = + container_of(work, struct panthor_aw, msg_retry_work);
drivers/gpu/drm/panthor/panthor_aw.c line 130
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +10
-0+struct panthor_am_msg *msg = &aw->msg; +int ret; + + ret =panthor_am_msg_retry (msg); +if (ret == -EINVAL ) +drm_warn (&aw->ptdev->base,"Send FIFO unexpectedly empty" ); + +if (ret == -EBUSY || ret == -EAGAIN ) +queue_work (aw->wq, &aw->msg_retry_work); +}
[Severity: Medium]
Does panthor_aw_msg_retry_work() spin in a zero-delay workqueue loop when panthor_am_msg_retry() returns -EBUSY?
When a second message is sent before the arbiter consumes the first from AM_OUTGOING_MESSAGE, panthor_am_msg_send() queues it in msg->send_fifo and schedules aw->msg_retry_work. As long as AM_OUTGOING_MESSAGE_STATUS stays non-zero, panthor_am_msg_retry() returns -EBUSY and the worker immediately re-queues itself onto aw->wq without any backoff or bound, pegging a kworker at 100% CPU polling MMIO registers (unlike rg_retry_messages() in panthor_resource_group.c, which uses delayed_work).
Quoted 38 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +38
-0+ +static void panthor_aw_send_msg (struct panthor_aw *aw,u64 message) +{ +struct panthor_device *ptdev = aw->ptdev; +int ret; + + ret =panthor_am_msg_send (&aw->msg, message); +if (ret == -ENOSPC ) +drm_err (&ptdev->base,"Send FIFO is full" ); + +if (ret == -EBUSY ) { +drm_dbg (&ptdev->base,"Pending messages, scheduling retry work" ); +queue_work (aw->wq, &aw->msg_retry_work); + } +} + +static void panthor_aw_handshake_handle (struct panthor_aw *aw,u64 message) +{ +struct panthor_device *ptdev = aw->ptdev; +bool acked =AM_MSG_ACK_GET (message); +u8 version =AM_MSG_VERSION_GET (message); +u8 reply_version =AM_MSG_CURRENT_VERSION ; +int ret; + + ret =panthor_am_msg_version_validate (&aw->msg, version, acked, + &reply_version); +if (ret == -EOPNOTSUPP ) +drm_warn (&ptdev->base, +"Msg protocol version less than minimum supported (%u < %u)" , + version,AM_MSG_MIN_SUPPORTED_VERSION ); + +if (!acked) { +u64 reply =VM_ARB_INIT_MAKE (1 , reply_version); + +panthor_aw_send_msg (aw, reply); + +guard (spinlock_irqsave)(&aw->lock); +
drivers/gpu/drm/panthor/panthor_aw.c line 178
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +10
-0+/* +* If state is GPU_REQUEST, arbiter previously completed +* handshake, New INIT could mean that the arbiter was restarted +* and we need to resend GPU_REQUEST. +*/ +if (atomic_read (&aw->state) ==PANTHOR_AW_STATE_GPU_REQUEST ) { +panthor_aw_send_msg (aw,VM_ARB_GPU_REQUEST ); +return ; + } + }
[Severity: Low]
Can this resend VM_ARB_GPU_REQUEST to an incompatible arbiter if the arbiter restarts with an unsupported protocol version while aw->state is PANTHOR_AW_STATE_GPU_REQUEST?
Even when panthor_am_msg_version_validate() returns -EOPNOTSUPP, the !acked branch still sends VM_ARB_GPU_REQUEST and returns early, leaving panthor_aw_request() waiting for the 5-second timeout instead of transitioning to PANTHOR_AW_STATE_READY so it can fail immediately with -EOPNOTSUPP. Also, panthor_am_msg_version_validate() returns -EOPNOTSUPP when acked is true and version > AM_MSG_CURRENT_VERSION, so the warning above can log that version is less than AM_MSG_MIN_SUPPORTED_VERSION when it is actually greater than AM_MSG_CURRENT_VERSION.
[ ... ]
Quoted 9 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +9
-0+ ret =panthor_aw_wait_cond (aw,atomic_read (&aw->state) != state, timeout_ms); +if (ret) { + scoped_guard(spinlock_irqsave, &aw->lock) { +switch (atomic_read (&aw->state)) { +case PANTHOR_AW_STATE_GPU_GRANTED : +return 0 ; +case PANTHOR_AW_STATE_GPU_REQUEST : +panthor_aw_state_set (aw,PANTHOR_AW_STATE_READY ); +break ;
drivers/gpu/drm/panthor/panthor_aw.c line 375
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +10
-0+default : +break ; + } + } + +return ret; + } + + goto again; +}
[Severity: Medium]
Can aw->state become permanently wedged in PANTHOR_AW_STATE_YIELDING if waiting for the window to close times out?
If __panthor_aw_suspend() times out waiting for PANTHOR_AW_STATE_READY (or if WINDOW_IRQ_WINDOW_OPENED arrives just after panthor_aw_request() times out in panthor_aw_resume() and transitions READY -> YIELDING), the caller suspends the AW IRQ while aw->state is PANTHOR_AW_STATE_YIELDING. If the hardware window finishes closing while the IRQ is masked, no WINDOW_IRQ_WINDOW_CLOSED interrupt fires on the next resume, and because neither __panthor_aw_suspend() nor panthor_aw_request() checks !panthor_aw_is_open(aw) or resets PANTHOR_AW_STATE_YIELDING to PANTHOR_AW_STATE_READY on timeout, every subsequent panthor_aw_request() call times out waiting on PANTHOR_AW_STATE_YIELDING.
Quoted 11 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +11
-0+ +static int __panthor_aw_suspend (struct panthor_aw *aw) +{ + scoped_guard(spinlock_irqsave, &aw->lock) { +switch (atomic_read (&aw->state)) { +case PANTHOR_AW_STATE_READY : +return 0 ; +case PANTHOR_AW_STATE_SUSPEND_PENDING : +return 0 ; +case PANTHOR_AW_STATE_GPU_GRANTED : +panthor_aw_state_set (aw,PANTHOR_AW_STATE_YIELDING );
drivers/gpu/drm/panthor/panthor_aw.c line 396
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +10
-0+panthor_aw_send_msg (aw,VM_ARB_GPU_STOPPED ); +break ; +default : +break ; + } + } + +return panthor_aw_state_wait (aw,PANTHOR_AW_STATE_READY , +PANTHOR_AW_STATE_TRANSITION_TIMEOUT_MS ); +}
[Severity: Medium]
What happens in __panthor_aw_suspend() when aw->state is PANTHOR_AW_STATE_INIT or PANTHOR_AW_STATE_GPU_REQUEST?
If the initial handshake in panthor_aw_init() -> panthor_aw_request() times out, aw->state is still PANTHOR_AW_STATE_INIT when panthor_aw_unplug() calls __panthor_aw_suspend(), which hits default and blocks for another 5 seconds waiting for PANTHOR_AW_STATE_READY. If __panthor_aw_suspend() is called while in PANTHOR_AW_STATE_GPU_REQUEST, it leaves the state as PANTHOR_AW_STATE_GPU_REQUEST while waiting for PANTHOR_AW_STATE_READY, so a concurrent WINDOW_IRQ_WINDOW_OPENED will transition it to PANTHOR_AW_STATE_GPU_GRANTED instead of yielding and cause suspend to time out with the window left open.
[ ... ]
Quoted 28 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +28
-0+int panthor_aw_resume (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; +int ret; + +if (!aw) +return 0 ; + +panthor_aw_irq_resume (&aw->irq); + + ret =panthor_aw_request (aw); +if (ret) { +drm_warn (&ptdev->base,"Timedout waiting for GPU to be granted" ); + goto err_out; + } + +return 0 ; + +err_out: +panthor_aw_irq_suspend (&aw->irq); +return ret; +} + +int panthor_aw_suspend (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; +int ret =0 ; +
drivers/gpu/drm/panthor/panthor_aw.c line 498
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c new file +10
-0+/* suspend hw components directly if AW is not supported */ +if (!aw) +return 0 ; + + ret =__panthor_aw_suspend (aw); + +panthor_aw_irq_suspend (&aw->irq); + +return ret; +}
[Severity: High]
Can aw->msg_retry_work run after panthor_aw_suspend() or the error path of panthor_aw_resume() returns and the caller disables the GPU clocks?
CPU0 kworkerpanthor_device_suspend()
...
panthor_aw_suspend()
__panthor_aw_suspend()
panthor_aw_send_msg()
queue_work(..., &msg_retry_work)
panthor_aw_irq_suspend() clk_disable_unprepare(ptdev->clks.core)
panthor_aw_msg_retry_work()
panthor_am_msg_retry()
gpu_read(msg->iomem, ...)
<-- unclocked MMIO access
Unlike panthor_aw_unplug(), neither panthor_aw_suspend() nor the err_out path of panthor_aw_resume() cancels aw->msg_retry_work, and panthor_aw_msg_retry_work() does not hold a runtime PM reference, so it can read and write msg->iomem after the clocks are turned off and trigger a synchronous external abort.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=22
PATCH v2 23/28 drm/panthor: Synchronize HW component PM transitions
In reply to Karunika ChooSplit hardware component suspend/resume from the top-level device PM path and protect those transitions with a dedicated mutex and state flag.
This lets access-window arbitration suspend or resume GPU components while runtime PM state remains controlled by the outer PM path.
--- drivers/gpu/drm/panthor/panthor_device.c | 50 +++++++++++++++++++++--- drivers/gpu/drm/panthor/panthor_device.h | 9 +++++ 2 files changed, 53 insertions(+), 6 deletions(-)
drivers/gpu/drm/panthor/panthor_device.c +44 -6
@@ -179,6 +179,10 @@ int panthor_device_init(struct panthor_device *ptdev)if (ret)return ret; + ret =drmm_mutex_init (&ptdev->base, &ptdev->pm.hw_component_lock); +if (ret) +return ret; + ret =drmm_mutex_init (&ptdev->base, &ptdev->pm.mmio_lock);if (ret)return ret;
@@ -293,6 +297,9 @@ int panthor_device_init(struct panthor_device *ptdev)if (ret) goto err_unplug_mmu; +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_ACTIVE ); + ret =panthor_sched_init (ptdev);if (ret) goto err_unplug_fw;
@@ -484,21 +491,55 @@ int panthor_device_mmap_io(struct panthor_device *ptdev, struct vm_area_struct *return 0 ; } -static int panthor_device_resume_hw_components (struct panthor_device *ptdev) +int panthor_device_suspend_hw_components (struct panthor_device *ptdev) +{ +guard (mutex)(&ptdev->pm.hw_component_lock); + +if (atomic_read (&ptdev->pm.hw_component_state) == +PANTHOR_DEVICE_PM_STATE_SUSPENDED ) +return 0 ; + +if (!pm_runtime_suspended (ptdev->base.dev)) { +panthor_fw_suspend (ptdev); +panthor_mmu_suspend (ptdev); +panthor_gpu_suspend (ptdev); +panthor_pwr_suspend (ptdev); + } + +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_SUSPENDED ); + +return 0 ; +} + +int panthor_device_resume_hw_components (struct panthor_device *ptdev) {int ret; +guard (mutex)(&ptdev->pm.hw_component_lock); + +if (atomic_read (&ptdev->pm.hw_component_state) == +PANTHOR_DEVICE_PM_STATE_ACTIVE ) +return 0 ; +panthor_pwr_resume (ptdev);panthor_gpu_resume (ptdev);panthor_mmu_resume (ptdev); ret =panthor_fw_resume (ptdev); -if (!ret) +if (!ret) { +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_ACTIVE );return 0 ; + }panthor_mmu_suspend (ptdev);panthor_gpu_suspend (ptdev);panthor_pwr_suspend (ptdev); + +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_SUSPENDED ); +return ret; }
@@ -609,10 +650,7 @@ int panthor_device_suspend(struct device *dev)* The end of the reset will happen in the resume path though. */ panthor_sched_suspend (ptdev); -panthor_fw_suspend (ptdev); -panthor_mmu_suspend (ptdev); -panthor_gpu_suspend (ptdev); -panthor_pwr_suspend (ptdev); +panthor_device_suspend_hw_components (ptdev);drm_dev_exit (cookie); }
drivers/gpu/drm/panthor/panthor_device.h +9 -0
@@ -353,6 +353,12 @@ struct panthor_device {/** @recovery_needed: True when a resume attempt failed. */ atomic_t recovery_needed; + +/** @hw_component_lock: Lock protects HW component PM state transitions */ +struct mutex hw_component_lock; + +/** @hw_component_state: HW component PM state */ +atomic_t hw_component_state; } pm;/** @profile_mask: User-set profiling flags for job accounting. */
@@ -442,6 +448,9 @@ int panthor_device_mmap_io(struct panthor_device *ptdev,int panthor_device_resume (struct device *dev);int panthor_device_suspend (struct device *dev); +int panthor_device_suspend_hw_components (struct panthor_device *ptdev); +int panthor_device_resume_hw_components (struct panthor_device *ptdev); +static inline int panthor_device_resume_and_get (struct panthor_device *ptdev) {int ret =pm_runtime_resume_and_get (ptdev->base.dev);
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 23/28] drm/panthor: Synchronize HW component PM transitions
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Medium] drm/panthor: missing slow-reset fallback in panthor_device_resume_hw_components() --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Medium] drm/panthor: missing slow-reset fallback in panthor_device_resume_hw_components()
--
commit b392fdf733ca625b6c9ab7dbb3e11caa5a1d1b14
Author: Karunika Choo <[email protected]>
drm/panthor: Synchronize HW component PM transitions
This commit splits hardware component suspend and resume into panthor_device_suspend_hw_components() and panthor_device_resume_hw_components(), serializing transitions with ptdev->pm.hw_component_lock and ptdev->pm.hw_component_state.
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_device.c +0
-0
[ ... ]
Quoted 47 lines
drivers/gpu/drm/panthor/panthor_device.c +32
-2@@ -484,21 +491,55 @@ int panthor_device_mmap_io(struct panthor_device *ptdev, struct vm_area_struct *return 0 ; } -static int panthor_device_resume_hw_components (struct panthor_device *ptdev) +int panthor_device_suspend_hw_components (struct panthor_device *ptdev) +{ +guard (mutex)(&ptdev->pm.hw_component_lock); + +if (atomic_read (&ptdev->pm.hw_component_state) == +PANTHOR_DEVICE_PM_STATE_SUSPENDED ) +return 0 ; + +if (!pm_runtime_suspended (ptdev->base.dev)) { +panthor_fw_suspend (ptdev); +panthor_mmu_suspend (ptdev); +panthor_gpu_suspend (ptdev); +panthor_pwr_suspend (ptdev); + } + +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_SUSPENDED ); + +return 0 ; +} + +int panthor_device_resume_hw_components (struct panthor_device *ptdev) {int ret; +guard (mutex)(&ptdev->pm.hw_component_lock); + +if (atomic_read (&ptdev->pm.hw_component_state) == +PANTHOR_DEVICE_PM_STATE_ACTIVE ) +return 0 ; +panthor_pwr_resume (ptdev);panthor_gpu_resume (ptdev);panthor_mmu_resume (ptdev); ret =panthor_fw_resume (ptdev); -if (!ret) +if (!ret) { +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_ACTIVE );return 0 ; + }
drivers/gpu/drm/panthor/panthor_device.c int panthor_device_mmap_io(struct panthor_device *ptdev, struct vm_area_struct * · line 544
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_device.c +4
-0panthor_mmu_suspend (ptdev);panthor_gpu_suspend (ptdev);panthor_pwr_suspend (ptdev); + +atomic_set (&ptdev->pm.hw_component_state, +PANTHOR_DEVICE_PM_STATE_SUSPENDED ); +return ret; }
[Severity: Medium]
Should the ptdev->reset.pending check and the fast-to-slow reset retry live inside panthor_device_resume_hw_components() under ptdev->pm.hw_component_lock rather than only in panthor_device_resume()?
drivers/gpu/drm/panthor/panthor_device.c:panthor_device_resume() {
...
if (atomic_read(&ptdev->reset.pending)) {
ptdev->reset.fast = false;
atomic_set(&ptdev->reset.pending, 0);
}
ret = panthor_device_resume_hw_components(ptdev);
if (ret && ptdev->reset.fast) {
drm_err(&ptdev->base, "Fast reset failed, trying a slow reset");
ptdev->reset.fast = false;
ret = panthor_device_resume_hw_components(ptdev);
}
...
}When access-window arbitration later calls panthor_device_resume_hw_components() while runtime PM remains active, panthor_device_resume() is not run. A pending reset in ptdev->reset.pending is then ignored, and a failed fast reset does not fall back to a slow reset by reloading firmware sections, causing component resume to fail. In panthor_device_resume(), ptdev->reset.fast is also modified outside ptdev->pm.hw_component_lock and the lock is dropped between the fast-reset attempt and the slow-reset retry.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=23
PATCH v2 24/28 drm/panthor: Quiesce scheduler tick during system suspend
In reply to Karunika ChooA scheduler tick can run during forced system suspend and access GPU registers after the clocks have been disabled.
Add system suspend callbacks that disable and drain tick work before forced suspend. Re-enable and queue a fresh tick after forced resume or when suspend fails.
--- drivers/gpu/drm/panthor/panthor_device.c | 26 ++++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_device.h | 3 +++ drivers/gpu/drm/panthor/panthor_drv.c | 8 ++++---- drivers/gpu/drm/panthor/panthor_sched.c | 15 ++++++++++++++ drivers/gpu/drm/panthor/panthor_sched.h | 2 ++ 5 files changed, 50 insertions(+), 4 deletions(-)
drivers/gpu/drm/panthor/panthor_device.c +26 -0
@@ -662,3 +662,29 @@ int panthor_device_suspend(struct device *dev)atomic_set (&ptdev->pm.state,PANTHOR_DEVICE_PM_STATE_SUSPENDED );return 0 ; } + +int panthor_device_system_suspend (struct device *dev) +{ +struct panthor_device *ptdev =dev_get_drvdata (dev); +int ret; + +panthor_sched_pre_suspend (ptdev); + + ret =pm_runtime_force_suspend (dev); +if (ret) +panthor_sched_post_resume (ptdev); + +return ret; +} + +int panthor_device_system_resume (struct device *dev) +{ +struct panthor_device *ptdev =dev_get_drvdata (dev); +int ret; + + ret =pm_runtime_force_resume (dev); + +panthor_sched_post_resume (ptdev); + +return ret; +}
drivers/gpu/drm/panthor/panthor_device.h +3 -0
@@ -448,6 +448,9 @@ int panthor_device_mmap_io(struct panthor_device *ptdev,int panthor_device_resume (struct device *dev);int panthor_device_suspend (struct device *dev); +int panthor_device_system_resume (struct device *dev); +int panthor_device_system_suspend (struct device *dev); +int panthor_device_suspend_hw_components (struct panthor_device *ptdev);int panthor_device_resume_hw_components (struct panthor_device *ptdev);
drivers/gpu/drm/panthor/panthor_drv.c +4 -4
@@ -1888,10 +1888,10 @@ static const struct of_device_id dt_match[] = { };MODULE_DEVICE_TABLE (of, dt_match); -static DEFINE_RUNTIME_DEV_PM_OPS(panthor_pm_ops, - panthor_device_suspend, - panthor_device_resume, - NULL); +static const struct dev_pm_ops panthor_pm_ops = { + SYSTEM_SLEEP_PM_OPS(panthor_device_system_suspend, panthor_device_system_resume) +RUNTIME_PM_OPS (panthor_device_suspend, panthor_device_resume,NULL ) +};static struct platform_driver panthor_driver = { .probe = panthor_probe,
drivers/gpu/drm/panthor/panthor_sched.c +15 -0
@@ -4047,6 +4047,21 @@ void panthor_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *sched DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_BOOKKEEP); } +void panthor_sched_pre_suspend (struct panthor_device *ptdev) +{ +struct panthor_scheduler *sched = ptdev->scheduler; + +disable_delayed_work_sync (&sched->tick_work); +} + +void panthor_sched_post_resume (struct panthor_device *ptdev) +{ +struct panthor_scheduler *sched = ptdev->scheduler; + +enable_delayed_work (&sched->tick_work); +panthor_sched_resume (ptdev); +} +void panthor_sched_unplug (struct panthor_device *ptdev) {struct panthor_scheduler *sched = ptdev->scheduler;
drivers/gpu/drm/panthor/panthor_sched.h +2 -0
@@ -49,6 +49,8 @@ void panthor_sched_pre_reset(struct panthor_device *ptdev);void panthor_sched_post_reset (struct panthor_device *ptdev,bool reset_failed);void panthor_sched_suspend (struct panthor_device *ptdev);void panthor_sched_resume (struct panthor_device *ptdev); +void panthor_sched_pre_suspend (struct panthor_device *ptdev); +void panthor_sched_post_resume (struct panthor_device *ptdev);void panthor_sched_report_mmu_fault (struct panthor_device *ptdev);void panthor_sched_prepare_for_vm_destruction (struct panthor_device *ptdev);
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 24/28] drm/panthor: Quiesce scheduler tick during system suspend
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Medium] drm/panthor: panthor_device_system_resume() wakes idle GPU via tick_work --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Medium] drm/panthor: panthor_device_system_resume() wakes idle GPU via tick_work
--
commit 4eba454e973401bba31950f161b35fd4637e2ab7
Author: Karunika Choo <[email protected]>
drm/panthor: Quiesce scheduler tick during system suspend
This commit adds system suspend and resume callbacks that disable the scheduler tick work before forced runtime suspend and re-enable it on resume or suspend failure.
Quoted 34 lines
drivers/gpu/drm/panthor/panthor_device.c +26
-0@@ -662,3 +662,29 @@ int panthor_device_suspend(struct device *dev)atomic_set (&ptdev->pm.state,PANTHOR_DEVICE_PM_STATE_SUSPENDED );return 0 ; } + +int panthor_device_system_suspend (struct device *dev) +{ +struct panthor_device *ptdev =dev_get_drvdata (dev); +int ret; + +panthor_sched_pre_suspend (ptdev); + + ret =pm_runtime_force_suspend (dev); +if (ret) +panthor_sched_post_resume (ptdev); + +return ret; +} + +int panthor_device_system_resume (struct device *dev) +{ +struct panthor_device *ptdev =dev_get_drvdata (dev); +int ret; + + ret =pm_runtime_force_resume (dev); + +panthor_sched_post_resume (ptdev); + +return ret; +}
[ ... ]
Quoted 12 lines
drivers/gpu/drm/panthor/panthor_sched.c +4
-0@@ -4047,6 +4047,21 @@ void panthor_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *sched DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_BOOKKEEP); } +void panthor_sched_pre_suspend (struct panthor_device *ptdev) +{ +struct panthor_scheduler *sched = ptdev->scheduler; +
drivers/gpu/drm/panthor/panthor_sched.c void panthor_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *sched · line 4063
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_sched.c +10
-0+disable_delayed_work_sync (&sched->tick_work); +} + +void panthor_sched_post_resume (struct panthor_device *ptdev) +{ +struct panthor_scheduler *sched = ptdev->scheduler; + +enable_delayed_work (&sched->tick_work); +panthor_sched_resume (ptdev); +}
[Severity: Medium]
Does calling panthor_sched_resume() unconditionally in panthor_sched_post_resume() force a runtime wakeup of an idle GPU on every system resume?
When the GPU is already runtime-suspended before system suspend, pm_runtime_force_resume() leaves the device in RPM_SUSPENDED without calling panthor_device_resume(). Calling panthor_sched_resume() queues sched->tick_work immediately, and tick_work() then calls panthor_device_resume_and_get(), powering up the GPU and queuing a second tick from panthor_device_resume().
In addition, if pm_runtime_force_resume() fails, queuing sched->tick_work causes tick_work() to immediately retry panthor_device_resume_and_get() and hit drm_WARN_ON(&ptdev->base, ret). Since panthor_device_resume() already calls panthor_sched_resume() when the device actually resumes, only the pm_runtime_force_suspend() error path needs to kick the tick if the device remained active.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=24
PATCH v2 25/28 drm/panthor: Route HW component PM through access windows
In reply to Karunika ChooMake access-window resume and suspend own GPU access when AW support is present, while keeping the direct HW component PM path for older GPUs.
Defer post-yield cleanup to workqueue context, and make panthor_device_resume_and_get() ensure that GPU access is obtained before callers touch hardware.
---
v2:
- Align with state lock changes.
- Fix case where autosuspend would not be triggered if tick_work drops its PM ref earlier and post_yield_work becomes the last PM ref holder.
- Fix case where post_yield_work could run after FW/MMU was unplugged.
- Wait for AW state transition before retrying runtime resume if -EAGAIN was received the first time around.
- Guard panthor_sched_resume against access if scheduler is not initialized or already torn down.
drivers/gpu/drm/panthor/panthor_aw.c | 146 ++++++++++++++++++++++- drivers/gpu/drm/panthor/panthor_aw.h | 6 + drivers/gpu/drm/panthor/panthor_device.c | 10 +- drivers/gpu/drm/panthor/panthor_device.h | 28 ++++- drivers/gpu/drm/panthor/panthor_sched.c | 3 + 5 files changed, 181 insertions(+), 12 deletions(-)
drivers/gpu/drm/panthor/panthor_aw.c +140 -6
@@ -81,6 +81,9 @@ struct panthor_aw {/** @msg_retry_work: Work to resend messages */ struct work_struct msg_retry_work; + +/** @post_yield_work: Work to yield the GPU */ +struct work_struct post_yield_work; };static bool panthor_aw_is_open (struct panthor_aw *aw)
@@ -114,6 +117,66 @@ static int panthor_aw_state_wait(struct panthor_aw *aw,return panthor_aw_wait_cond (aw,atomic_read (&aw->state) == target, timeout_ms); } +static int panthor_aw_state_wait_transition (struct panthor_aw *aw,u32 timeout_ms) +{ +return panthor_aw_wait_cond ( + aw, + (atomic_read (&aw->state) ==PANTHOR_AW_STATE_READY || +atomic_read (&aw->state) ==PANTHOR_AW_STATE_GPU_GRANTED ), + timeout_ms); +} + +static void panthor_aw_post_yield_work (struct work_struct *work) +{ +struct panthor_aw *aw = + container_of(work, struct panthor_aw, post_yield_work); +struct panthor_device *ptdev = aw->ptdev; +struct device *dev = ptdev->base.dev; +int ret; + + scoped_guard(spinlock_irqsave, &aw->lock) { +/* Something else has progressed the state to READY. */ +if (atomic_read (&aw->state) !=PANTHOR_AW_STATE_SUSPEND_PENDING ) +return ; + } + +/* +* Ensure in-progress resume is completed and prevent future RPM suspend +* to keep the clocks turned on when accessing HW registers. +*/ +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); + + ret =panthor_device_suspend_hw_components (ptdev); +if (ret) +dev_warn (dev,"Failed to suspend hardware components." ); + + scoped_guard(spinlock_irqsave, &aw->lock) +panthor_aw_state_set (aw,PANTHOR_AW_STATE_READY ); + +/* +* schedule an immediate tick to re-evaluate if there is any additional +* work. This will request access to the GPU again and if the driver has +* gone idle, it will yield GPU access via the runtime suspend path. +*/ +panthor_sched_resume (ptdev); + +pm_runtime_put_autosuspend (dev); +} + +static bool panthor_aw_schedule_post_yield_work (struct panthor_aw *aw) +{ +lockdep_assert_held (&aw->lock); + +if (panthor_aw_state_try_set (aw,PANTHOR_AW_STATE_GPU_GRANTED , +PANTHOR_AW_STATE_SUSPEND_PENDING )) { +queue_work (aw->wq, &aw->post_yield_work); +return true; + } + +return false; +} +static void panthor_aw_msg_retry_work (struct work_struct *work) { struct panthor_aw *aw =
@@ -213,7 +276,7 @@ static void panthor_aw_handle_window_closed(struct panthor_aw *aw)switch (atomic_read (&aw->state)) {case PANTHOR_AW_STATE_GPU_GRANTED : -/* TODO: schedule cleanup */ +panthor_aw_schedule_post_yield_work (aw);break ;case PANTHOR_AW_STATE_GPU_REQUEST :/*
@@ -416,6 +479,7 @@ int panthor_aw_init(struct panthor_device *ptdev) aw->iomem = ptdev->iomem;INIT_WORK (&aw->msg_retry_work, panthor_aw_msg_retry_work); +INIT_WORK (&aw->post_yield_work, panthor_aw_post_yield_work);init_waitqueue_head (&aw->waitqueue);spin_lock_init (&aw->lock);
@@ -443,6 +507,16 @@ int panthor_aw_init(struct panthor_device *ptdev)return ret; } +void panthor_aw_cancel (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; + +if (!aw) +return ; + +disable_work_sync (&aw->post_yield_work); +} +void panthor_aw_unplug (struct panthor_device *ptdev) {struct panthor_aw *aw = ptdev->aw;
@@ -456,6 +530,7 @@ void panthor_aw_unplug(struct panthor_device *ptdev) }disable_work_sync (&aw->msg_retry_work); +panthor_aw_cancel (ptdev); }int panthor_aw_resume (struct panthor_device *ptdev)
@@ -463,21 +538,41 @@ int panthor_aw_resume(struct panthor_device *ptdev)struct panthor_aw *aw = ptdev->aw;int ret; +/* resume hw components directly if AW is not supported */ if (!aw) -return 0 ; +return panthor_device_resume_hw_components (ptdev);panthor_aw_irq_resume (&aw->irq); +again: ret =panthor_aw_request (aw); +if (ret) + goto err_out; + + ret =panthor_device_resume_hw_components (ptdev);if (ret) { -drm_warn (&ptdev->base,"Timedout waiting for GPU to be granted" ); +/* Yield GPU access if HW components failed to resume */ +__panthor_aw_suspend (aw); goto err_out; } -return 0 ; +switch (atomic_read (&aw->state)) { +case PANTHOR_AW_STATE_SUSPEND_PENDING : +/* +* WINDOW_CLOSED won the race. Suspend components before the +* caller can disable clocks. post_yield_work will transition +* state to READY after this PM transition completes. +*/ +panthor_device_suspend_hw_components (ptdev); + ret = -EAGAIN ; +break ; +case PANTHOR_AW_STATE_GPU_GRANTED : +return 0 ; +default : + goto again; + } err_out: -panthor_aw_irq_suspend (&aw->irq);return ret; }
@@ -488,11 +583,50 @@ int panthor_aw_suspend(struct panthor_device *ptdev)/* suspend hw components directly if AW is not supported */ if (!aw) -return 0 ; +return panthor_device_suspend_hw_components (ptdev); + + ret =panthor_device_suspend_hw_components (ptdev); +if (ret) + goto out_irq_suspend; ret =__panthor_aw_suspend (aw); +out_irq_suspend:panthor_aw_irq_suspend (&aw->irq);return ret; } + +int panthor_aw_wait_transition_complete (struct panthor_device *ptdev) +{ +/* +* This is only called from panthor_device_resume_and_get. If the error +* condition with which this is called changes in the future, the return +* value needs reconsidering. +*/ +if (!ptdev->aw) +return -EAGAIN ; + +return panthor_aw_state_wait_transition ( + ptdev->aw,PANTHOR_AW_STATE_TRANSITION_TIMEOUT_MS ); +} + +int panthor_aw_ensure_gpu_access (struct panthor_device *ptdev) +{ +int ret; + +if (!ptdev->aw) +return 0 ; + +again: + ret =panthor_aw_resume (ptdev); +if (ret != -EAGAIN ) +return ret; + + ret =panthor_aw_state_wait_transition ( + ptdev->aw,PANTHOR_AW_STATE_TRANSITION_TIMEOUT_MS ); +if (ret) +return ret; + + goto again; +}
drivers/gpu/drm/panthor/panthor_aw.h +6 -0
@@ -35,8 +35,14 @@ int panthor_aw_init(struct panthor_device *ptdev);void panthor_aw_unplug (struct panthor_device *ptdev); +void panthor_aw_cancel (struct panthor_device *ptdev); +int panthor_aw_resume (struct panthor_device *ptdev);int panthor_aw_suspend (struct panthor_device *ptdev); +int panthor_aw_wait_transition_complete (struct panthor_device *ptdev); + +int panthor_aw_ensure_gpu_access (struct panthor_device *ptdev); +#endif
drivers/gpu/drm/panthor/panthor_device.c +7 -3
@@ -92,6 +92,7 @@ void panthor_device_unplug(struct panthor_device *ptdev)*/ mutex_unlock (&ptdev->unplug.lock); +panthor_aw_cancel (ptdev);/* Now, try to cleanly shutdown the GPU before the device resources * get reclaimed. */
@@ -325,6 +326,7 @@ int panthor_device_init(struct panthor_device *ptdev)panthor_sched_unplug (ptdev); err_unplug_fw: +panthor_aw_cancel (ptdev);panthor_fw_unplug (ptdev); err_unplug_mmu:
@@ -577,15 +579,17 @@ int panthor_device_resume(struct device *dev)atomic_set (&ptdev->reset.pending,0 ); } - ret =panthor_device_resume_hw_components (ptdev); + ret =panthor_aw_resume (ptdev);if (ret && ptdev->reset.fast) {drm_err (&ptdev->base,"Fast reset failed, trying a slow reset" ); ptdev->reset.fast = false; - ret =panthor_device_resume_hw_components (ptdev); + ret =panthor_aw_resume (ptdev); }if (!ret)panthor_sched_resume (ptdev); +else +panthor_aw_suspend (ptdev);drm_dev_exit (cookie);
@@ -650,7 +654,7 @@ int panthor_device_suspend(struct device *dev)* The end of the reset will happen in the resume path though. */ panthor_sched_suspend (ptdev); -panthor_device_suspend_hw_components (ptdev); +panthor_aw_suspend (ptdev);drm_dev_exit (cookie); }
drivers/gpu/drm/panthor/panthor_device.h +25 -3
@@ -20,6 +20,7 @@#include <drm/panthor_drm.h> #include "panthor_device_io.h" +#include "panthor_aw.h" struct panthor_aw ;struct panthor_csf ;
@@ -456,7 +457,10 @@ int panthor_device_resume_hw_components(struct panthor_device *ptdev);static inline int panthor_device_resume_and_get (struct panthor_device *ptdev) { -int ret =pm_runtime_resume_and_get (ptdev->base.dev); +int ret; + +again: + ret =pm_runtime_resume_and_get (ptdev->base.dev);/* If the resume failed, we need to clear the runtime_error, which * can done by forcing the RPM state to suspended. If multiple
@@ -470,8 +474,26 @@ static inline int panthor_device_resume_and_get(struct panthor_device *ptdev)* succeeded. Given resume errors are not expected, this is probably * something we can live with. */ -if (ret &&atomic_cmpxchg (&ptdev->pm.recovery_needed,1 ,0 ) ==1 ) -pm_runtime_set_suspended (ptdev->base.dev); +if (ret) { +if (atomic_cmpxchg (&ptdev->pm.recovery_needed,1 ,0 ) ==1 ) +pm_runtime_set_suspended (ptdev->base.dev); + +if (ret == -EAGAIN ) { + ret =panthor_aw_wait_transition_complete (ptdev); +if (ret) +return ret; + + goto again; + } + +return ret; + } + + ret =panthor_aw_ensure_gpu_access (ptdev); +if (ret) { +pm_runtime_put_autosuspend (ptdev->base.dev); +return ret; + }return ret; }
drivers/gpu/drm/panthor/panthor_sched.c +3 -0
@@ -2889,6 +2889,9 @@ void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev)void panthor_sched_resume (struct panthor_device *ptdev) { +if (!ptdev->scheduler) +return ; +/* Force a tick to re-evaluate after a resume. */ sched_queue_delayed_work (ptdev->scheduler, tick,0 ); }
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 25/28] drm/panthor: Route HW component PM through access windows
Thank you for your contribution! Sashiko AI review found 6 potential issues to consider: - [High] drm/panthor: missing panthor_sched_suspend() in panthor_aw_post_yield_work() - [High] drm/panthor…
Thank you for your contribution! Sashiko AI review found 6 potential issues to consider:
- [High] drm/panthor: missing panthor_sched_suspend() in panthor_aw_post_yield_work()
- [High] drm/panthor: race between panthor_aw_ensure_gpu_access() and post_yield_work
- [High] drm/panthor: endless AW yield-request ping-pong from panthor_aw_post_yield_work()
- [Medium] drm/panthor: panthor_device_resume() treats -EAGAIN as fast-reset failure
- [Medium] drm/panthor: __panthor_aw_suspend() leaves state as SUSPEND_PENDING
- [Medium] drm/panthor: unhandled -EAGAIN from panthor_aw_resume() on PM paths
--
commit 4fae2615b4ec401e9748b231f8ea063e488e1f9a
Author: Karunika Choo <[email protected]>
drm/panthor: Route HW component PM through access windows
This commit routes hardware component suspend and resume through the access window layer when AW support is present, defers post-yield cleanup to a workqueue, and updates panthor_device_resume_and_get() to ensure GPU access is granted before returning.
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_aw.c +0
-0
[ ... ]
Quoted 16 lines
drivers/gpu/drm/panthor/panthor_aw.c +12
-0@@ -114,6 +117,66 @@ static int panthor_aw_state_wait(struct panthor_aw *aw,return panthor_aw_wait_cond (aw,atomic_read (&aw->state) == target, timeout_ms); } +static int panthor_aw_state_wait_transition (struct panthor_aw *aw,u32 timeout_ms) +{ +return panthor_aw_wait_cond ( + aw, + (atomic_read (&aw->state) ==PANTHOR_AW_STATE_READY || +atomic_read (&aw->state) ==PANTHOR_AW_STATE_GPU_GRANTED ), + timeout_ms); +} + +static void panthor_aw_post_yield_work (struct work_struct *work) +{ + struct panthor_aw *aw =
drivers/gpu/drm/panthor/panthor_aw.c static int panthor_aw_state_wait(struct panthor_aw *aw, · line 141
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c +10
-0+ container_of(work, struct panthor_aw, post_yield_work); +struct panthor_device *ptdev = aw->ptdev; +struct device *dev = ptdev->base.dev; +int ret; + + scoped_guard(spinlock_irqsave, &aw->lock) { +/* Something else has progressed the state to READY. */ +if (atomic_read (&aw->state) !=PANTHOR_AW_STATE_SUSPEND_PENDING ) +return ; + }
[Severity: Medium]
Does any other path ever transition aw->state from PANTHOR_AW_STATE_SUSPEND_PENDING to PANTHOR_AW_STATE_READY?
When panthor_aw_suspend() runs after a WINDOW_CLOSED interrupt sets PANTHOR_AW_STATE_SUSPEND_PENDING, it suspends the hardware components and calls __panthor_aw_suspend(), which returns 0 on PANTHOR_AW_STATE_SUSPEND_PENDING without updating aw->state:
drivers/gpu/drm/panthor/panthor_aw.c:__panthor_aw_suspend() {
scoped_guard(spinlock_irqsave, &aw->lock) {
switch (atomic_read(&aw->state)) {
case PANTHOR_AW_STATE_READY:
return 0;
case PANTHOR_AW_STATE_SUSPEND_PENDING:
return 0;
...
}Because aw->state remains PANTHOR_AW_STATE_SUSPEND_PENDING after runtime suspend finishes, panthor_aw_post_yield_work() does not exit early here and calls panthor_sched_resume(), which schedules tick_work and wakes the suspended GPU back up. If system resume (pm_runtime_force_resume()) runs before post_yield_work instead, panthor_aw_resume() sees PANTHOR_AW_STATE_SUSPEND_PENDING and fails system resume with -EAGAIN.
drivers/gpu/drm/panthor/panthor_aw.c static int panthor_aw_state_wait(struct panthor_aw *aw, · line 152
Quoted 11 lines
drivers/gpu/drm/panthor/panthor_aw.c +11
-0+ +/* +* Ensure in-progress resume is completed and prevent future RPM suspend +* to keep the clocks turned on when accessing HW registers. +*/ +pm_runtime_get_noresume (dev); +pm_runtime_barrier (dev); + + ret =panthor_device_suspend_hw_components (ptdev); +if (ret) +dev_warn (dev,"Failed to suspend hardware components." );
[Severity: High]
Doesn't panthor_aw_post_yield_work() need to suspend or unbind scheduler groups before calling panthor_device_suspend_hw_components()?
Unlike panthor_device_suspend(), which calls panthor_sched_suspend() before panthor_aw_suspend(), panthor_aw_post_yield_work() leaves groups bound in sched->csg_slots[] with group->csg_id >= 0 while panthor_device_suspend_hw_components() stops the MCU and calls panthor_mmu_suspend(). panthor_mmu_suspend() disables all active address spaces and calls panthor_vm_release_as_locked(), resetting vm->as.id = -1 and vm->as.active_cnt = 0 on those still-bound groups.
On the next scheduler tick after hardware components resume, tick_ctx_apply() sees group->csg_id >= 0 and skips group_bind_locked(), panthor_vm_active(), and CSG programming, leaving the bound groups unmapped in the MMU and unconfigured on the rebooted MCU. When those groups are later unbound in group_unbind_locked(), panthor_vm_idle() decrements vm->as.active_cnt from 0 (underflowing refcount_t) and hits drm_WARN_ON(&ptdev->base, vm->as.id == -1). In addition, if runtime suspend runs before the hardware components are resumed again, panthor_device_suspend() will call panthor_sched_suspend() while the MCU is stopped and the access window is closed.
drivers/gpu/drm/panthor/panthor_aw.c static int panthor_aw_state_wait(struct panthor_aw *aw, · line 165
Quoted 13 lines
drivers/gpu/drm/panthor/panthor_aw.c +13
-0+ + scoped_guard(spinlock_irqsave, &aw->lock) +panthor_aw_state_set (aw,PANTHOR_AW_STATE_READY ); + +/* +* schedule an immediate tick to re-evaluate if there is any additional +* work. This will request access to the GPU again and if the driver has +* gone idle, it will yield GPU access via the runtime suspend path. +*/ +panthor_sched_resume (ptdev); + +pm_runtime_put_autosuspend (dev); +}
[Severity: High]
Can calling panthor_sched_resume() unconditionally here cause an endless request/yield livelock between two idle access windows sharing a partition?
When AW0 is idle inside its 50ms autosuspend window and AW1 requests the GPU, the arbiter issues PART_CMD_YIELD_IDLE and FW v2 closes AW0's window, scheduling panthor_aw_post_yield_work() on AW0. panthor_sched_resume() then queues tick_work with delay 0, and tick_work() calls panthor_device_resume_and_get() -> panthor_aw_ensure_gpu_access() -> panthor_aw_request() before checking whether AW0 has any runnable groups.
Sending VM_ARB_GPU_REQUEST from idle AW0 causes the arbiter to issue PART_CMD_YIELD_IDLE to AW1. Once AW1 finishes its work and yields to AW0, AW1's panthor_aw_post_yield_work() likewise requests the GPU back from AW0, while AW0's tick_work() finds no runnable work and resets its 50ms autosuspend timer via pm_runtime_put_autosuspend(). Both access windows can then ping-pong GPU ownership and hardware component suspend/resume indefinitely without ever reaching runtime autosuspend.
[ ... ]
Quoted 35 lines
drivers/gpu/drm/panthor/panthor_aw.c +19
-3@@ -463,21 +538,41 @@ int panthor_aw_resume(struct panthor_device *ptdev)struct panthor_aw *aw = ptdev->aw;int ret; +/* resume hw components directly if AW is not supported */ if (!aw) -return 0 ; +return panthor_device_resume_hw_components (ptdev);panthor_aw_irq_resume (&aw->irq); +again: ret =panthor_aw_request (aw); +if (ret) + goto err_out; + + ret =panthor_device_resume_hw_components (ptdev);if (ret) { -drm_warn (&ptdev->base,"Timedout waiting for GPU to be granted" ); +/* Yield GPU access if HW components failed to resume */ +__panthor_aw_suspend (aw); goto err_out; } -return 0 ; +switch (atomic_read (&aw->state)) { +case PANTHOR_AW_STATE_SUSPEND_PENDING : +/* +* WINDOW_CLOSED won the race. Suspend components before the +* caller can disable clocks. post_yield_work will transition +* state to READY after this PM transition completes. +*/ +panthor_device_suspend_hw_components (ptdev); + ret = -EAGAIN ; +break ;
drivers/gpu/drm/panthor/panthor_aw.c int panthor_aw_resume(struct panthor_device *ptdev) · line 577
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c +5
-1+case PANTHOR_AW_STATE_GPU_GRANTED : +return 0 ; +default : + goto again; + } err_out: -panthor_aw_irq_suspend (&aw->irq);return ret; }
[Severity: High]
Can panthor_aw_ensure_gpu_access() -> panthor_aw_resume() race with panthor_aw_post_yield_work() when the device is already RPM_ACTIVE?
panthor_aw_post_yield_work() uses pm_runtime_barrier(dev) to wait for an in-progress runtime resume, but panthor_device_resume_and_get() calls panthor_aw_ensure_gpu_access() after pm_runtime_resume_and_get() has already set the device to RPM_ACTIVE. In that state pm_runtime_barrier(dev) returns immediately, and nothing serializes panthor_aw_resume() against panthor_aw_post_yield_work() or a second caller of panthor_aw_ensure_gpu_access():
CPU0 CPU1 (kworker / second caller)panthor_aw_ensure_gpu_access()
panthor_aw_resume()
panthor_device_resume_hw_components()
/* WINDOW_CLOSED sets SUSPEND_PENDING */
switch (atomic_read(&aw->state))
case PANTHOR_AW_STATE_SUSPEND_PENDING:
panthor_aw_post_yield_work()
pm_runtime_barrier() /* no-op */
panthor_device_suspend_hw_components()
panthor_aw_state_set(READY)
panthor_aw_ensure_gpu_access()
panthor_aw_resume()
panthor_aw_request() /* GRANTED */
panthor_device_resume_hw_components()
return 0
panthor_device_suspend_hw_components()
<-- suspends FW/MMU/GPU/PWR while CPU1 is using the GPUAlternatively, if WINDOW_CLOSED fires after panthor_aw_request() succeeds on CPU0 but before CPU0 takes hw_component_lock in panthor_device_resume_hw_components(), panthor_aw_post_yield_work() can finish and set aw->state to PANTHOR_AW_STATE_READY first; CPU0 then resumes hardware components while the window is closed, sees PANTHOR_AW_STATE_READY, and takes
default: goto again without suspending them.
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_device.c +0
-0
[ ... ]
drivers/gpu/drm/panthor/panthor_device.c int panthor_device_resume(struct device *dev) · line 587
Quoted 12 lines
drivers/gpu/drm/panthor/panthor_device.c +2
-2@@ -577,15 +579,17 @@ int panthor_device_resume(struct device *dev)atomic_set (&ptdev->reset.pending,0 ); } - ret =panthor_device_resume_hw_components (ptdev); + ret =panthor_aw_resume (ptdev);if (ret && ptdev->reset.fast) {drm_err (&ptdev->base,"Fast reset failed, trying a slow reset" ); ptdev->reset.fast = false; - ret =panthor_device_resume_hw_components (ptdev); + ret =panthor_aw_resume (ptdev); }
[Severity: Medium]
Does panthor_device_resume() treat -EAGAIN from panthor_aw_resume() as a fast-reset failure?
When panthor_aw_resume() returns -EAGAIN because aw->state is PANTHOR_AW_STATE_SUSPEND_PENDING, panthor_device_resume() logs a false fast reset error, clears ptdev->reset.fast = false (forcing a full firmware reload on the next resume), and immediately retries panthor_aw_resume() while the device is still RPM_RESUMING and panthor_aw_post_yield_work() is still blocked in pm_runtime_barrier(dev), so the retry is guaranteed to fail with -EAGAIN as well. Conversely, when panthor_device_resume_hw_components() is called from panthor_aw_ensure_gpu_access() -> panthor_aw_resume() while the device is already RPM_ACTIVE, there is no fallback to retry with ptdev->reset.fast = false if a fast reset fails.
drivers/gpu/drm/panthor/panthor_device.c int panthor_device_resume(struct device *dev) · line 594
Quoted 7 lines
drivers/gpu/drm/panthor/panthor_device.c +2
-0if (!ret)panthor_sched_resume (ptdev); +else +panthor_aw_suspend (ptdev);drm_dev_exit (cookie);
[Severity: Medium]
What happens when panthor_device_resume() returns -EAGAIN to callers other than panthor_device_resume_and_get()?
panthor_device_resume_and_get() catches -EAGAIN, waits with panthor_aw_wait_transition_complete(), and retries, but panthor_device_unplug() calls pm_runtime_get_sync() directly (triggering drm_WARN_ON() and proceeding with unplug while suspended) and panthor_device_system_resume() calls pm_runtime_force_resume() directly (failing system resume and leaving the device suspended).
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=25
PATCH v2 26/28 drm/panthor: Tolerate access-window loss during HW waits
In reply to Karunika ChooAn access window can close while Panthor waits for a cache flush, power transition or firmware boot. After access loss, these operations may not report completion.
Add a helper to check whether the access window has GPU access. Suppress timeout errors in cache-flush and power-control waits after access loss. Allow firmware boot and MCU halt waits to end when GPU access is lost.
Wake firmware waiters from the access-window interrupt handler. Publish the firmware pointer after initializing its wait queue.
Skip scheduler processing of firmware events while GPU access is unavailable.
---
v2:
- Notify FW waitqueue on WINDOW_CLOSED to make waiters re-evaluate state instead of waiting until timeout.
- Use smp_store_release() and smp_load_acquire() to ensure waitqueue initialization is visible to the AW-close handler before it attempts to wake the waitqueue.
- Bail early on MCU halt wait.
drivers/gpu/drm/panthor/panthor_aw.c | 9 +++++++++ drivers/gpu/drm/panthor/panthor_aw.h | 2 ++ drivers/gpu/drm/panthor/panthor_fw.c | 20 +++++++++++++++--- drivers/gpu/drm/panthor/panthor_fw.h | 2 ++ drivers/gpu/drm/panthor/panthor_gpu.c | 4 +++- drivers/gpu/drm/panthor/panthor_pwr.c | 27 +++++++++++++++++++------ drivers/gpu/drm/panthor/panthor_sched.c | 3 +++ 7 files changed, 57 insertions(+), 10 deletions(-)
drivers/gpu/drm/panthor/panthor_aw.c +9 -0
@@ -340,6 +340,7 @@ static irqreturn_t panthor_aw_irq_raw_hander(int irq, void *data)if (status &WINDOW_IRQ_WINDOW_OPENED )panthor_aw_handle_window_opened (aw); +panthor_fw_notify_waitqueue (ptdev);gpu_write (pirq->iomem,INT_CLEAR , status);return IRQ_HANDLED ;
@@ -630,3 +631,11 @@ int panthor_aw_ensure_gpu_access(struct panthor_device *ptdev) goto again; } + +bool panthor_aw_has_gpu_access (struct panthor_device *ptdev) +{ +if (!ptdev->aw) +return true; + +return (atomic_read (&ptdev->aw->state) ==PANTHOR_AW_STATE_GPU_GRANTED ); +}
drivers/gpu/drm/panthor/panthor_aw.h +2 -0
@@ -45,4 +45,6 @@ int panthor_aw_wait_transition_complete(struct panthor_device *ptdev);int panthor_aw_ensure_gpu_access (struct panthor_device *ptdev); +bool panthor_aw_has_gpu_access (struct panthor_device *ptdev); +#endif
drivers/gpu/drm/panthor/panthor_fw.c +17 -3
@@ -1140,9 +1140,10 @@ static int panthor_fw_start(struct panthor_device *ptdev)gpu_write (fw->iomem,MCU_CONTROL ,MCU_CONTROL_AUTO );if (!wait_event_timeout (ptdev->fw->req_waitqueue, - ptdev->fw->booted, + (ptdev->fw->booted || + !panthor_aw_has_gpu_access (ptdev)),msecs_to_jiffies (1000 ))) { -if (!ptdev->fw->booted && +if (!ptdev->fw->booted &&panthor_aw_has_gpu_access (ptdev) && !(gpu_read (fw->irq.iomem,INT_STAT ) &JOB_INT_GLOBAL_IF )) timedout = true; }
@@ -1180,6 +1181,9 @@ static bool panthor_fw_mcu_halted(struct panthor_device *ptdev)struct panthor_fw_global_iface *glb_iface =panthor_fw_get_glb_iface (ptdev);bool halted; +if (!panthor_aw_has_gpu_access (ptdev)) +return true; + halted =gpu_read (ptdev->fw->iomem,MCU_STATUS ) ==MCU_STATUS_HALT ;if (panthor_fw_has_glb_state (ptdev))
@@ -1223,6 +1227,16 @@ static void panthor_fw_mcu_set_active(struct panthor_device *ptdev)panthor_fw_update_reqs (glb_iface, req,0 ,GLB_HALT ); } +void panthor_fw_notify_waitqueue (struct panthor_device *ptdev) +{ +struct panthor_fw *fw =smp_load_acquire (&ptdev->fw); + +if (!fw) +return ; + +wake_up_all (&fw->req_waitqueue); +} +/** * panthor_fw_pre_reset() - Call before a reset. * @ptdev: Device.
@@ -1501,10 +1515,10 @@ int panthor_fw_init(struct panthor_device *ptdev)return -ENOMEM ; fw->iomem = ptdev->iomem + ptdev->hw->regs.mcu_control.offset; - ptdev->fw = fw;init_waitqueue_head (&fw->req_waitqueue);INIT_LIST_HEAD (&fw->sections);INIT_DELAYED_WORK (&fw->watchdog.ping_work, panthor_fw_ping_work); +smp_store_release (&ptdev->fw, fw); irq =platform_get_irq_byname (to_platform_device (ptdev->base.dev),"job" );if (irq <=0 )
drivers/gpu/drm/panthor/panthor_fw.h +2 -0
@@ -513,6 +513,8 @@ panthor_fw_alloc_suspend_buf_mem(struct panthor_device *ptdev, size_t size);struct panthor_vm *panthor_fw_vm (struct panthor_device *ptdev); +void panthor_fw_notify_waitqueue (struct panthor_device *ptdev); +void panthor_fw_pre_reset (struct panthor_device *ptdev,bool on_hang);int panthor_fw_post_reset (struct panthor_device *ptdev);
drivers/gpu/drm/panthor/panthor_gpu.c +3 -1
@@ -18,6 +18,7 @@#include <drm/drm_managed.h> #include <drm/drm_print.h> +#include "panthor_aw.h" #include "panthor_device.h" #include "panthor_gpu.h" #include "panthor_gpu_regs.h"
@@ -377,7 +378,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, msecs_to_jiffies(100))) { scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {if ((ptdev->gpu->pending_reqs &GPU_IRQ_CLEAN_CACHES_COMPLETED ) !=0 && - !(gpu_read (gpu->irq.iomem,INT_RAWSTAT ) &GPU_IRQ_CLEAN_CACHES_COMPLETED )) + !(gpu_read (gpu->irq.iomem,INT_RAWSTAT ) & +GPU_IRQ_CLEAN_CACHES_COMPLETED ) &&panthor_aw_has_gpu_access (ptdev)) ret = -ETIMEDOUT ;else ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED ;
drivers/gpu/drm/panthor/panthor_pwr.c +21 -6
@@ -10,6 +10,7 @@#include <drm/drm_managed.h> #include <drm/drm_print.h> +#include "panthor_aw.h" #include "panthor_device.h" #include "panthor_gpu_regs.h" #include "panthor_hw.h"
@@ -122,7 +123,8 @@ static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd) msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {guard (spinlock_irqsave)(&ptdev->pwr->reqs_lock); -if (reset_pending (ptdev) && !reset_irq_raised (ptdev)) { +if (reset_pending (ptdev) && !reset_irq_raised (ptdev) && +panthor_aw_has_gpu_access (ptdev)) {drm_err (&ptdev->base,"RESET timed out (0x%x)" , reset_cmd);return -ETIMEDOUT ; }
@@ -279,9 +281,14 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd,panthor_pwr_write_command (ptdev, pwr_cmd, mask); - ret =gpu_read64_poll_timeout (pwr->iomem, ready_reg, val, (mask & val) == expected_val, + ret =gpu_read64_poll_timeout (pwr->iomem, ready_reg, val, + ((mask & val) == expected_val || + !panthor_aw_has_gpu_access (ptdev)),100 , timeout_us);if (ret) { +if (!panthor_aw_has_gpu_access (ptdev)) +return 0 ; +drm_err (&ptdev->base,"timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)" ,get_domain_name (domain), pwr_cmd, mask);
@@ -343,9 +350,13 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain)* allow-flag will be set with delegated-flag being cleared. */ ret =gpu_read64_poll_timeout (pwr->iomem,PWR_STATUS , val, - ((delegated_mask | allow_mask) & val) == allow_mask,10 , -PWR_TRANSITION_TIMEOUT_US ); + (((delegated_mask | allow_mask) & val) == allow_mask || + !panthor_aw_has_gpu_access (ptdev)), +10 ,PWR_TRANSITION_TIMEOUT_US );if (ret) { +if (!panthor_aw_has_gpu_access (ptdev)) +return 0 ; +drm_err (&ptdev->base,"Retracting %s domain timeout, cmd(0x%x)" ,get_domain_name (domain), pwr_cmd);return ret;
@@ -400,9 +411,13 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain)* allow-flag will be cleared with delegated-flag being set. */ ret =gpu_read64_poll_timeout (pwr->iomem,PWR_STATUS , val, - ((delegated_mask | allow_mask) & val) == delegated_mask, + (((delegated_mask | allow_mask) & val) == delegated_mask || + !panthor_aw_has_gpu_access (ptdev)),10 ,PWR_TRANSITION_TIMEOUT_US );if (ret) { +if (!panthor_aw_has_gpu_access (ptdev)) +return 0 ; +drm_err (&ptdev->base,"Delegating %s domain timeout, cmd(0x%x)" ,get_domain_name (domain), pwr_cmd);return ret;
@@ -542,7 +557,7 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev)const bool has_neural =panthor_hw_has_neural (ptdev);/* Abort if L2 power off constraints are not satisfied */ -if (!(pwr_status & l2_allow_mask)) { +if (!(pwr_status & l2_allow_mask) &&panthor_aw_has_gpu_access (ptdev)) {drm_warn (&ptdev->base,"Power off L2 domain not allowed" );return ; }
drivers/gpu/drm/panthor/panthor_sched.c +3 -0
@@ -1887,6 +1887,9 @@ void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events)guard (spinlock)(&ptdev->scheduler->events_lock); +if (!panthor_aw_has_gpu_access (ptdev)) +return ; +if (events &JOB_INT_GLOBAL_IF ) {sched_process_global_irq_locked (ptdev); events &= ~JOB_INT_GLOBAL_IF ;
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 26/28] drm/panthor: Tolerate access-window loss during HW waits
Thank you for your contribution! Sashiko AI review found 5 potential issues to consider: - [High] drm/panthor: false success in panthor_fw_start() and panthor_fw_mcu_halted() - [High] drm/panthor…
Thank you for your contribution! Sashiko AI review found 5 potential issues to consider:
- [High] drm/panthor: false success in panthor_fw_start() and panthor_fw_mcu_halted()
- [High] drm/panthor: panthor_sched_report_fw_events() drops FW events on access loss
- [Medium] drm/panthor: unguarded PWR_STATUS checks fail on access loss in panthor_pwr.c
- [Medium] drm/panthor: unawakened waits stall on access loss in flush, reset, and FW
- [Low] drm/panthor: missing early return on access loss in panthor_pwr_l2_power_off()
--
commit d06b3bf7778829600d32bed288afa3f04bcf72dd
Author: Karunika Choo <[email protected]>
drm/panthor: Tolerate access-window loss during HW waits
This commit adds panthor_aw_has_gpu_access() and updates firmware, GPU cache flush, power control, and scheduler paths to stop waiting or suppress timeout errors when the access window closes.
Quoted 18 lines
drivers/gpu/drm/panthor/panthor_fw.c +3
-2@@ -1140,9 +1140,10 @@ static int panthor_fw_start(struct panthor_device *ptdev)gpu_write (fw->iomem,MCU_CONTROL ,MCU_CONTROL_AUTO );if (!wait_event_timeout (ptdev->fw->req_waitqueue, - ptdev->fw->booted, + (ptdev->fw->booted || + !panthor_aw_has_gpu_access (ptdev)),msecs_to_jiffies (1000 ))) { -if (!ptdev->fw->booted && +if (!ptdev->fw->booted &&panthor_aw_has_gpu_access (ptdev) && !(gpu_read (fw->irq.iomem,INT_STAT ) &JOB_INT_GLOBAL_IF )) timedout = true; }
drivers/gpu/drm/panthor/panthor_fw.c static bool panthor_fw_mcu_halted(struct panthor_device *ptdev) · line 1187
Quoted 7 lines
drivers/gpu/drm/panthor/panthor_fw.c +3
-0@@ -1180,6 +1181,9 @@ static bool panthor_fw_mcu_halted(struct panthor_device *ptdev)struct panthor_fw_global_iface *glb_iface =panthor_fw_get_glb_iface (ptdev);bool halted; +if (!panthor_aw_has_gpu_access (ptdev)) +return true; + halted =gpu_read (ptdev->fw->iomem,MCU_STATUS ) ==MCU_STATUS_HALT ;
[Severity: High]
Can returning 0 from panthor_fw_start() and true from panthor_fw_mcu_halted() on access loss cause callers to treat an unbooted MCU as booted and corrupt ptdev->reset.fast?
If the access window closes in panthor_fw_start() before JOB_INT_GLOBAL_IF sets ptdev->fw->booted, panthor_fw_start() returns 0 while ptdev->fw->booted is still false. In panthor_fw_init(), execution continues into panthor_fw_init_ifaces() before the MCU has populated the shared control interface. In panthor_aw_resume() -> panthor_device_resume_hw_components() -> panthor_fw_post_reset(), an interrupted slow reset (where ptdev->reset.fast was false and firmware sections were freshly reloaded) succeeds and is immediately followed by panthor_device_suspend_hw_components() -> panthor_fw_pre_reset(). Because panthor_fw_mcu_halted() unconditionally returns true when !panthor_aw_has_gpu_access(ptdev), panthor_fw_pre_reset() sets ptdev->reset.fast = true even though the MCU never finished booting, so the next resume skips panthor_reload_fw_sections() and attempts a fast reset on unbooted firmware memory.
Quoted 5 lines
drivers/gpu/drm/panthor/panthor_gpu.c +0
-0
drivers/gpu/drm/panthor/panthor_gpu.c int panthor_gpu_flush_caches(struct panthor_device *ptdev, · line 385
Quoted 9 lines
drivers/gpu/drm/panthor/panthor_gpu.c +2
-1@@ -377,7 +378,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev, msecs_to_jiffies(100))) { scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {if ((ptdev->gpu->pending_reqs &GPU_IRQ_CLEAN_CACHES_COMPLETED ) !=0 && - !(gpu_read (gpu->irq.iomem,INT_RAWSTAT ) &GPU_IRQ_CLEAN_CACHES_COMPLETED )) + !(gpu_read (gpu->irq.iomem,INT_RAWSTAT ) & +GPU_IRQ_CLEAN_CACHES_COMPLETED ) &&panthor_aw_has_gpu_access (ptdev)) ret = -ETIMEDOUT ;else ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED ;
[Severity: Medium]
Does panthor_gpu_flush_caches() still block for the full 100ms timeout per active VM whenever the access window closes?
When panthor_aw_handle_window_closed() sets aw->state to PANTHOR_AW_STATE_SUSPEND_PENDING and schedules panthor_aw_post_yield_work(), panthor_device_suspend_hw_components() -> panthor_mmu_suspend() -> panthor_mmu_as_disable() calls panthor_gpu_flush_caches() for each bound MMU address space slot while holding ptdev->mmu->as.slots_lock and ptdev->pm.hw_component_lock. Because panthor_gpu_flush_caches() only checks panthor_aw_has_gpu_access(ptdev) after wait_event_timeout() expires (and ptdev->gpu->reqs_acked is not woken on access-window close), every yield sleeps for 100ms per active VM. Similarly, panthor_pwr_reset() and panthor_fw_wait_acks() do not include !panthor_aw_has_gpu_access(ptdev) in their wait_event_timeout() conditions, so in-flight waits there also sleep until their full timeout expires when access is lost.
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_pwr.c +0
-0
[ ... ]
Quoted 5 lines
drivers/gpu/drm/panthor/panthor_pwr.c +0
-1@@ -400,9 +411,13 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain)* allow-flag will be cleared with delegated-flag being set. */ ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val, - ((delegated_mask | allow_mask) & val) == delegated_mask,
drivers/gpu/drm/panthor/panthor_pwr.c static int delegate_domain(struct panthor_device *ptdev, u32 domain) · line 423
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_pwr.c +5
-0+ (((delegated_mask | allow_mask) & val) == delegated_mask || + !panthor_aw_has_gpu_access (ptdev)), 10, PWR_TRANSITION_TIMEOUT_US);if (ret) { +if (!panthor_aw_has_gpu_access (ptdev)) +return 0 ; +drm_err (&ptdev->base,"Delegating %s domain timeout, cmd(0x%x)" ,get_domain_name (domain), pwr_cmd);return ret;
[Severity: Medium]
What happens in panthor_pwr_l2_power_on() when panthor_pwr_domain_transition() or delegate_domain() returns 0 after losing GPU access?
panthor_pwr_l2_power_on() powers on the L2 domain and then calls panthor_pwr_delegate_domains(), which runs delegate_domain() for the neural, shader, and tiler domains in sequence. Once the access window closes, MMIO reads from PWR_STATUS return 0, so the next delegate_domain() call hits the unguarded !(pwr_status & allow_mask) check at the start of the function, logs a warning, and fails with -EPERM. The initial PWR_STATUS checks in panthor_pwr_l2_power_on() and panthor_pwr_reset_soft() have the same issue and fail with -EPERM and -EOPNOTSUPP when entered after access loss.
drivers/gpu/drm/panthor/panthor_pwr.c void panthor_pwr_l2_power_off(struct panthor_device *ptdev) · line 563
Quoted 9 lines
drivers/gpu/drm/panthor/panthor_pwr.c +1
-1@@ -542,7 +557,7 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev)const bool has_neural =panthor_hw_has_neural (ptdev);/* Abort if L2 power off constraints are not satisfied */ -if (!(pwr_status & l2_allow_mask)) { +if (!(pwr_status & l2_allow_mask) &&panthor_aw_has_gpu_access (ptdev)) {drm_warn (&ptdev->base,"Power off L2 domain not allowed" );return ; }
[Severity: Low]
Should panthor_pwr_l2_power_off() still return early when GPU access is lost, while only gating drm_warn() on panthor_aw_has_gpu_access(ptdev)?
With the condition written this way, calling panthor_pwr_l2_power_off() when !panthor_aw_has_gpu_access(ptdev) (such as during panthor_aw_post_yield_work() -> panthor_device_suspend_hw_components() -> panthor_gpu_suspend()) bypasses the return and falls through to panthor_pwr_domain_force_off() and panthor_pwr_domain_power_off() across all domains on a closed access window.
Quoted 5 lines
drivers/gpu/drm/panthor/panthor_sched.c +0
-0
drivers/gpu/drm/panthor/panthor_sched.c void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events) · line 1895
Quoted 9 lines
drivers/gpu/drm/panthor/panthor_sched.c +3
-0@@ -1887,6 +1887,9 @@ void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events)guard (spinlock)(&ptdev->scheduler->events_lock); +if (!panthor_aw_has_gpu_access (ptdev)) +return ; +if (events &JOB_INT_GLOBAL_IF ) {sched_process_global_irq_locked (ptdev); events &= ~JOB_INT_GLOBAL_IF ;
[Severity: High]
Can returning early here drop job completions and CSG events when the MCU raises a job IRQ just before yielding the access window?
kthread (job irq) <hardirq> (aw irq)panthor_job_irq_handler()
status = gpu_read(INT_RAWSTAT)
gpu_write(INT_CLEAR, status)
panthor_aw_irq_raw_hander()
panthor_aw_handle_window_closed()
aw->state =
PANTHOR_AW_STATE_SUSPEND_PENDING panthor_sched_report_fw_events()
if (!panthor_aw_has_gpu_access(ptdev))
return; <-- drops status events
With YIELD_IDLE enabled, the MCU updates group sync objects and CSG output structures in host DRAM, raises the job interrupt, and immediately yields the access window. Because panthor_job_irq_handler() has already cleared the interrupt before calling panthor_sched_report_fw_events(), bailing out when !panthor_aw_has_gpu_access(ptdev) discards those events (such as CSG_SYNC_UPDATE and CS_FAULT) even though the global and CSG interfaces live in shared DRAM, leaving completed jobs' dma_fences unsignaled across fast resets.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=26
PATCH v2 27/28 drm/panthor: Prevent missed post-yield cleanup due to reset
In reply to Karunika ChooGPU resets can generate access-window events that trigger normal post-yield cleanup. Firmware can also yield GPU access during reset.
Add a RESET_ACTIVE access-window state. Enter this state only from GPU_GRANTED. Ignore window-open and window-close events while reset is active. Use the hardware window status to check GPU access during reset.
After reset, schedule post-yield cleanup if the hardware window is closed.
Abort reset preparation when the access window is not GPU_GRANTED. Suppress firmware restart errors when GPU access has been lost.
Clear pending PWR_IRQ_RESET_COMPLETED flags on resume to prevent blocking future legitimate resets from executing.
---
v2:
- Return state transition outcome from panthor_aw_pre_reset to allow reset worker to bail the reset early.
- Make unplug decision due to reset failure before drm_dev_exit()
- Make panthor_aw_has_gpu-access check HW window status if in RESET_ACTIVE state to allow waiters to bail during reset if WINDOW was closed.
- Defensively clear PWR_IRQ_RESET_COMPLETED on resume to prevent state de-sync.
drivers/gpu/drm/panthor/panthor_aw.c | 50 +++++++++++++++++++++++- drivers/gpu/drm/panthor/panthor_aw.h | 7 ++++ drivers/gpu/drm/panthor/panthor_device.c | 13 ++++++ drivers/gpu/drm/panthor/panthor_pwr.c | 7 ++++ 4 files changed, 76 insertions(+), 1 deletion(-)
drivers/gpu/drm/panthor/panthor_aw.c +49 -1
@@ -275,6 +275,9 @@ static void panthor_aw_handle_window_closed(struct panthor_aw *aw)return ;switch (atomic_read (&aw->state)) { +case PANTHOR_AW_STATE_RESET_ACTIVE : +/* Ignore this WINDOW_CLOSED as part of reset operation. */ +return ;case PANTHOR_AW_STATE_GPU_GRANTED :panthor_aw_schedule_post_yield_work (aw);break ;
@@ -302,6 +305,9 @@ static void panthor_aw_handle_window_opened(struct panthor_aw *aw)return ;switch (atomic_read (&aw->state)) { +case PANTHOR_AW_STATE_RESET_ACTIVE : +/* Ignore this WINDOW_OPENED as part of reset operation. */ +return ;case PANTHOR_AW_STATE_GPU_GRANTED :case PANTHOR_AW_STATE_SUSPEND_PENDING :case PANTHOR_AW_STATE_INIT :
@@ -388,6 +394,7 @@ static int panthor_aw_request(struct panthor_aw *aw)switch (state) {case PANTHOR_AW_STATE_GPU_GRANTED :return 0 ; +case PANTHOR_AW_STATE_RESET_ACTIVE :case PANTHOR_AW_STATE_SUSPEND_PENDING :return -EAGAIN ;case PANTHOR_AW_STATE_INIT :
@@ -637,5 +644,46 @@ bool panthor_aw_has_gpu_access(struct panthor_device *ptdev)if (!ptdev->aw)return true; -return (atomic_read (&ptdev->aw->state) ==PANTHOR_AW_STATE_GPU_GRANTED ); +switch (atomic_read (&ptdev->aw->state)) { +case PANTHOR_AW_STATE_GPU_GRANTED : +return true; +case PANTHOR_AW_STATE_RESET_ACTIVE : +return panthor_aw_is_open (ptdev->aw); +default : +break ; + } + +return false; +} + +int panthor_aw_pre_reset (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; + +if (!aw) +return 0 ; + +guard (spinlock_irqsave)(&aw->lock); + +if (!panthor_aw_state_try_set (ptdev->aw,PANTHOR_AW_STATE_GPU_GRANTED , +PANTHOR_AW_STATE_RESET_ACTIVE )) +return -EAGAIN ; + +return 0 ; +} + +void panthor_aw_post_reset (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; + +if (!aw) +return ; + +guard (spinlock_irqsave)(&aw->lock); + +panthor_aw_state_try_set (aw,PANTHOR_AW_STATE_RESET_ACTIVE , +PANTHOR_AW_STATE_GPU_GRANTED ); + +if (!panthor_aw_is_open (aw)) +panthor_aw_schedule_post_yield_work (aw); }
drivers/gpu/drm/panthor/panthor_aw.h +7 -0
@@ -24,6 +24,9 @@ enum panthor_aw_state {/** @PANTHOR_AW_STATE_GPU_GRANTED: AW is granted GPU access. */ PANTHOR_AW_STATE_GPU_GRANTED , +/** @PANTHOR_AW_STATE_RESET_ACTIVE: AW is being reset. */ +PANTHOR_AW_STATE_RESET_ACTIVE , +/** @PANTHOR_AW_STATE_YIELDING: Stopped GPU access, pending close. */ PANTHOR_AW_STATE_YIELDING,
@@ -47,4 +50,8 @@ int panthor_aw_ensure_gpu_access(struct panthor_device *ptdev);bool panthor_aw_has_gpu_access (struct panthor_device *ptdev); +int panthor_aw_pre_reset (struct panthor_device *ptdev); + +void panthor_aw_post_reset (struct panthor_device *ptdev); +#endif
drivers/gpu/drm/panthor/panthor_device.c +13 -0
@@ -140,14 +140,27 @@ static void panthor_device_reset_work(struct work_struct *work)return ;panthor_sched_pre_reset (ptdev); +if (panthor_aw_pre_reset (ptdev) == -EAGAIN ) { +atomic_set (&ptdev->reset.pending,0 ); +panthor_sched_post_reset (ptdev, false); + goto out_dev_exit; + }panthor_fw_pre_reset (ptdev, true);panthor_mmu_pre_reset (ptdev); +panthor_hw_soft_reset (ptdev); +panthor_hw_l2_power_on (ptdev);panthor_mmu_post_reset (ptdev); ret =panthor_fw_post_reset (ptdev); +if (ret && !panthor_aw_has_gpu_access (ptdev)) + ret =0 ; + +panthor_aw_post_reset (ptdev);atomic_set (&ptdev->reset.pending,0 );panthor_sched_post_reset (ptdev, ret !=0 ); + +out_dev_exit:drm_dev_exit (cookie);if (ret) {
drivers/gpu/drm/panthor/panthor_pwr.c +7 -0
@@ -113,6 +113,9 @@ static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)if (reset_pending (ptdev)) {drm_WARN (&ptdev->base,1 ,"Reset already pending" ); }else { +if (!panthor_aw_has_gpu_access (ptdev)) +return 0 ; + ptdev->pwr->pending_reqs |=PWR_IRQ_RESET_COMPLETED ;gpu_write (pwr->irq.iomem,INT_CLEAR ,PWR_IRQ_RESET_COMPLETED );panthor_pwr_write_command (ptdev, reset_cmd,0 );
@@ -622,5 +625,9 @@ void panthor_pwr_resume(struct panthor_device *ptdev)if (!ptdev->pwr)return ; +/* clear any pending resets on resume to prevent blocking future resets */ +scoped_guard (spinlock_irqsave, &ptdev->pwr->reqs_lock) + ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED; +panthor_irq_resume (&ptdev->pwr->irq); }
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 27/28] drm/panthor: Prevent missed post-yield cleanup due to reset
Thank you for your contribution! Sashiko AI review found 7 potential issues to consider: - [High] drm/panthor: panthor_sched_pre_reset() runs before panthor_aw_pre_reset() - [High] drm/panthor: lost…
Thank you for your contribution! Sashiko AI review found 7 potential issues to consider:
- [High] drm/panthor: panthor_sched_pre_reset() runs before panthor_aw_pre_reset()
- [High] drm/panthor: lost slow reset in panthor_device_reset_work() on AW loss
- [High] drm/panthor: race between panthor_device_reset_work() and AW HW component PM
- [Medium] drm/panthor: panthor_aw_post_reset() sets GPU_GRANTED before checking window
- [Medium] drm/panthor: panthor_pwr_reset_soft() fails before GPU access check
- [Medium] drm/panthor: panthor_pwr_reset() leaves PWR_IRQ_RESET_COMPLETED set on timeout
- [Medium] drm/panthor: unhandled AW reset events in panthor_gpu_suspend()
--
commit 04a925f0f5b623c17e694b1b19489978a653cb56
Author: Karunika Choo <[email protected]>
drm/panthor: Prevent missed post-yield cleanup due to reset
This commit adds a PANTHOR_AW_STATE_RESET_ACTIVE state to ignore reset-induced access-window events during GPU resets and schedule post-yield cleanup afterward if the hardware window closed.
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_aw.c +0
-0
[ ... ]
Quoted 1 line
drivers/gpu/drm/panthor/panthor_aw.c +0
-0@@ -637,5 +644,46 @@ bool panthor_aw_has_gpu_access(struct panthor_device *ptdev)
[ ... ]
Quoted 5 lines
drivers/gpu/drm/panthor/panthor_aw.c +5
-0+int panthor_aw_pre_reset (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; + +if (!aw)
drivers/gpu/drm/panthor/panthor_aw.c bool panthor_aw_has_gpu_access(struct panthor_device *ptdev) · line 673
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c +10
-0+return 0 ; + +guard (spinlock_irqsave)(&aw->lock); + +if (!panthor_aw_state_try_set (ptdev->aw,PANTHOR_AW_STATE_GPU_GRANTED , +PANTHOR_AW_STATE_RESET_ACTIVE )) +return -EAGAIN ; + +return 0 ; +}
[Severity: High]
Can panthor_device_reset_work() race with panthor_device_resume_hw_components() when an access window is re-granted while runtime PM is active?
When an access window yields while ptdev->pm.state is PANTHOR_DEVICE_PM_STATE_ACTIVE, panthor_aw_post_yield_work() suspends the hardware components under ptdev->pm.hw_component_lock while ptdev->pm.state stays active. On the next panthor_aw_resume(), panthor_aw_request() sets aw->state to PANTHOR_AW_STATE_GPU_GRANTED before panthor_device_resume_hw_components() acquires ptdev->pm.hw_component_lock:
kworker (reset.work) caller (panthor_aw_resume)
panthor_aw_request()
<hardirq>
panthor_aw_handle_window_opened()
aw->state = GPU_GRANTED
panthor_device_reset_work()
panthor_aw_pre_reset()
aw->state = RESET_ACTIVE panthor_mmu_pre_reset()
panthor_device_resume_hw_components()
panthor_gpu_resume() panthor_mmu_resume()
panthor_hw_soft_reset()
panthor_mmu_post_reset() panthor_fw_resume() <-- concurrent reset/resume
Because neither panthor_device_reset_work() nor panthor_aw_pre_reset() synchronizes with ptdev->pm.hw_component_lock or checks ptdev->pm.hw_component_state, the reset worker can reset the GPU, MMU, and firmware while panthor_device_resume_hw_components() is concurrently resuming them, corrupting ptdev->mmu->as.alloc_mask and causing firmware boot failure that triggers panthor_device_unplug().
Quoted 6 lines
drivers/gpu/drm/panthor/panthor_aw.c +6
-0+ +void panthor_aw_post_reset (struct panthor_device *ptdev) +{ +struct panthor_aw *aw = ptdev->aw; + +if (!aw)
drivers/gpu/drm/panthor/panthor_aw.c bool panthor_aw_has_gpu_access(struct panthor_device *ptdev)
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_aw.c +10
-0+return ; + +guard (spinlock_irqsave)(&aw->lock); + +panthor_aw_state_try_set (aw,PANTHOR_AW_STATE_RESET_ACTIVE , +PANTHOR_AW_STATE_GPU_GRANTED ); + +if (!panthor_aw_is_open (aw)) +panthor_aw_schedule_post_yield_work (aw); +}
[Severity: Medium]
If the hardware access window closed during the reset, does calling panthor_aw_state_try_set() before panthor_aw_is_open() briefly expose a false PANTHOR_AW_STATE_GPU_GRANTED state and wake aw->waitqueue?
panthor_aw_state_try_set() sets aw->state to PANTHOR_AW_STATE_GPU_GRANTED and calls wake_up_all(&aw->waitqueue) before panthor_aw_is_open() checks WINDOW_STATUS and transitions aw->state to PANTHOR_AW_STATE_SUSPEND_PENDING. Lockless readers such as panthor_aw_has_gpu_access(), panthor_aw_resume(), and panthor_aw_state_wait_transition() do not take aw->lock, so they can observe PANTHOR_AW_STATE_GPU_GRANTED and proceed as if GPU access were held even though the window is closed.
In addition, when panthor_aw_post_reset() transitions aw->state to PANTHOR_AW_STATE_SUSPEND_PENDING, any pending WINDOW_CLOSED interrupt that fires afterward will hit the default branch in panthor_aw_handle_window_closed() and warn "Unexpected WINDOW_CLOSED received" because PANTHOR_AW_STATE_SUSPEND_PENDING is not handled there (unlike in panthor_aw_handle_window_opened()).
drivers/gpu/drm/panthor/panthor_device.c static void panthor_device_reset_work(struct work_struct *work) · line 147
Quoted 13 lines
drivers/gpu/drm/panthor/panthor_device.c +5
-0@@ -140,14 +140,27 @@ static void panthor_device_reset_work(struct work_struct *work)return ;panthor_sched_pre_reset (ptdev); +if (panthor_aw_pre_reset (ptdev) == -EAGAIN ) { +atomic_set (&ptdev->reset.pending,0 ); +panthor_sched_post_reset (ptdev, false); + goto out_dev_exit; + }
[Severity: High]
Should panthor_aw_pre_reset() run before panthor_sched_pre_reset()?
panthor_aw_post_yield_work() suspends hardware components without calling panthor_sched_suspend(), so user groups remain bound to CSG slots while the access window is closed. When panthor_sched_pre_reset() runs before panthor_aw_pre_reset() has verified PANTHOR_AW_STATE_GPU_GRANTED, panthor_sched_suspend() rings CSF_GLB_DOORBELL_ID over the closed window and waits in panthor_fw_csg_wait_acks() -> panthor_fw_wait_acks(), which does not check panthor_aw_has_gpu_access(). Every bound CSG times out on CSG_STATE_SUSPEND, escalates to CSG_STATE_TERMINATE, and marks innocent user groups asPANTHOR_CS_GROUP_TERMINATED. Furthermore, if panthor_aw_post_yield_work() already ran panthor_mmu_suspend() (which resets vm->as.active_cnt to 0 via panthor_vm_release_as_locked()), unbinding those groups in panthor_sched_suspend() calls panthor_vm_idle() and underflows vm->as.active_cnt.
Even when aw->state starts in PANTHOR_AW_STATE_GPU_GRANTED, running panthor_sched_pre_reset() before transitioning to PANTHOR_AW_STATE_RESET_ACTIVE means a WINDOW_CLOSED event arriving while CSGs are suspending will schedule post_yield_work concurrently with the reset.
drivers/gpu/drm/panthor/panthor_device.c static void panthor_device_reset_work(struct work_struct *work) · line 151
Quoted 4 lines
drivers/gpu/drm/panthor/panthor_device.c +1
-0panthor_fw_pre_reset (ptdev, true);panthor_mmu_pre_reset (ptdev); +panthor_hw_soft_reset (ptdev);
[Severity: Medium]
Does panthor_gpu_suspend() also need PANTHOR_AW_STATE_RESET_ACTIVE protection when it calls panthor_hw_soft_reset()?
drivers/gpu/drm/panthor/panthor_gpu.c:panthor_gpu_suspend() {
...
if (!ptdev->reset.fast)
panthor_hw_soft_reset(ptdev);
else
panthor_hw_l2_power_off(ptdev);
panthor_gpu_irq_suspend(ptdev);
}When panthor_aw_suspend() (or the error path of panthor_aw_resume()) calls panthor_device_suspend_hw_components() after a failed MCU halt or slow-reset boot failure, panthor_gpu_suspend() executes panthor_hw_soft_reset() while aw->state is still PANTHOR_AW_STATE_GPU_GRANTED. The reset-induced WINDOW_CLOSED interrupt transitions aw->state to PANTHOR_AW_STATE_SUSPEND_PENDING and queues post_yield_work, so the subsequent __panthor_aw_suspend() sees PANTHOR_AW_STATE_SUSPEND_PENDING and returns 0 without sending VM_ARB_GPU_STOPPED, leaving the hardware window open and the arbiter out of sync with aw->state once post_yield_work sets PANTHOR_AW_STATE_READY.
drivers/gpu/drm/panthor/panthor_device.c static void panthor_device_reset_work(struct work_struct *work) · line 160
Quoted 9 lines
drivers/gpu/drm/panthor/panthor_device.c +5
-0+panthor_hw_l2_power_on (ptdev);panthor_mmu_post_reset (ptdev); ret =panthor_fw_post_reset (ptdev); +if (ret && !panthor_aw_has_gpu_access (ptdev)) + ret =0 ; + +panthor_aw_post_reset (ptdev);atomic_set (&ptdev->reset.pending,0 );
[Severity: High]
When a reset is aborted at panthor_aw_pre_reset() or loses GPU access before panthor_fw_post_reset() completes, does clearing ptdev->reset.pending cause the next resume to skip a required slow reset?
When the access window closes, panthor_aw_post_yield_work() runs panthor_fw_suspend() -> panthor_fw_pre_reset(ptdev, false):
drivers/gpu/drm/panthor/panthor_fw.c:panthor_fw_pre_reset() {
...
ptdev->reset.fast = false;
if (!on_hang) {
panthor_fw_halt_mcu(ptdev);
if (!panthor_fw_wait_mcu_halted(ptdev))
drm_warn(&ptdev->base, "Failed to cleanly suspend MCU");
else
ptdev->reset.fast = true;
}
...
}Because panthor_fw_mcu_halted() returns true whenever !panthor_aw_has_gpu_access(ptdev), panthor_fw_pre_reset(ptdev, false) sets ptdev->reset.fast = true even though the MCU was never cleanly halted (or failed to boot during panthor_fw_post_reset()). With ptdev->reset.pending also cleared to 0 here and in the -EAGAIN branch above, the subsequent panthor_aw_resume() or panthor_device_resume() performs a fast reset instead of reloading the firmware sections.
Quoted 5 lines
drivers/gpu/drm/panthor/panthor_pwr.c +0
-0
drivers/gpu/drm/panthor/panthor_pwr.c static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd) · line 121
Quoted 9 lines
drivers/gpu/drm/panthor/panthor_pwr.c +3
-0@@ -113,6 +113,9 @@ static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)if (reset_pending (ptdev)) {drm_WARN (&ptdev->base,1 ,"Reset already pending" ); }else { +if (!panthor_aw_has_gpu_access (ptdev)) +return 0 ; + ptdev->pwr->pending_reqs |=PWR_IRQ_RESET_COMPLETED ;gpu_write (pwr->irq.iomem,INT_CLEAR ,PWR_IRQ_RESET_COMPLETED );panthor_pwr_write_command (ptdev, reset_cmd,0 );
[Severity: Medium]
Can panthor_pwr_reset() reach this panthor_aw_has_gpu_access() check when the access window is already closed?
Its caller panthor_pwr_reset_soft() reads PWR_STATUS first:
drivers/gpu/drm/panthor/panthor_pwr.c:panthor_pwr_reset_soft() {
...
if (!(gpu_read64(pwr->iomem, PWR_STATUS) & PWR_STATUS_ALLOW_SOFT_RESET)) {
drm_err(&ptdev->base, "RESET_SOFT not allowed");
return -EOPNOTSUPP;
}
return panthor_pwr_reset(ptdev, PWR_COMMAND_RESET_SOFT);
}When GPU access is lost, gpu_read64(pwr->iomem, PWR_STATUS) reads 0 over the closed window, so panthor_pwr_reset_soft() logs a false "RESET_SOFT not allowed" error and returns -EOPNOTSUPP before calling panthor_pwr_reset(). panthor_pwr_l2_power_on(), called right after panthor_hw_soft_reset() in panthor_device_reset_work(), similarly reads PWR_STATUS as 0 without checking panthor_aw_has_gpu_access() and logs a false "Power on L2 domain not allowed" warning.
drivers/gpu/drm/panthor/panthor_pwr.c void panthor_pwr_resume(struct panthor_device *ptdev) · line 633
Quoted 10 lines
drivers/gpu/drm/panthor/panthor_pwr.c +4
-0@@ -622,5 +625,9 @@ void panthor_pwr_resume(struct panthor_device *ptdev)if (!ptdev->pwr)return ; +/* clear any pending resets on resume to prevent blocking future resets */ +scoped_guard (spinlock_irqsave, &ptdev->pwr->reqs_lock) + ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED; +panthor_irq_resume (&ptdev->pwr->irq); }
[Severity: Medium]
Should panthor_pwr_reset() also clear PWR_IRQ_RESET_COMPLETED before returning -ETIMEDOUT?
drivers/gpu/drm/panthor/panthor_pwr.c:panthor_pwr_reset() {
...
if (!wait_event_timeout(ptdev->pwr->reqs_acked, !reset_pending(ptdev),
msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {
guard(spinlock_irqsave)(&ptdev->pwr->reqs_lock);
if (reset_pending(ptdev) && !reset_irq_raised(ptdev) &&
panthor_aw_has_gpu_access(ptdev)) {
drm_err(&ptdev->base, "RESET timed out (0x%x)", reset_cmd);
return -ETIMEDOUT;
}
ptdev->pwr->pending_reqs &= ~PWR_IRQ_RESET_COMPLETED;
}
}If the access window closes during panthor_pwr_reset() (aborting the hardware reset) and re-opens before the 500ms wait_event_timeout() expires, panthor_aw_has_gpu_access() is true both in panthor_pwr_reset() and in panthor_aw_post_reset(). panthor_pwr_reset() returns -ETIMEDOUT without clearing PWR_IRQ_RESET_COMPLETED, and panthor_aw_post_reset() sees the open window and does not schedule post_yield_work, so panthor_pwr_resume() never runs and future panthor_pwr_reset() calls hit drm_WARN("Reset already pending") without issuing the reset command.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=27
PATCH v2 28/28 drm/panthor: Reset partitions before starting arbitration
In reply to Karunika ChooA partition may still have an open access window when the arbiter starts (typically from restarting the driver), while its software state assumes no active window. Starting arbitration in this state can leave software out of sync with the hardware.
Recover each partition to RESET before enabling its interrupts. Allow open windows to yield, fall back to forced close if necessary, and bound recovery attempts so failure aborts initialization.
Keep partition interrupts masked during recovery and clean up before normal operation begins.
--- .../arbitration/panthor_partition_control.c | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+)
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +54 -0
@@ -43,6 +43,7 @@#define PART_REG_POLL_SLEEP_US 10#define PART_STATE_TRANSITION_TIMEOUT_US 5000000 +#define PART_ENSURE_RESET_RETRY_COUNT 3/** struct panthor_partition_cmd - Partition command data */ struct panthor_partition_cmd {
@@ -368,6 +369,54 @@ void panthor_partition_control_term(struct panthor_arbitration *adev) } } +static int partition_ensure_reset (struct panthor_partition_control *pc) +{ +int ret =0 ; +int count =0 ; + +again: +if ((count >=PART_ENSURE_RESET_RETRY_COUNT ) && + (partition_state_get (pc) !=PART_STATE_RESET )) +return -ETIMEDOUT ; + + count++; + +switch (partition_state_get (pc)) { +case PART_STATE_RESET : +/* clear any remnants of this operation */ +gpu_write (pc->iomem,AM_PART_IRQ_CLEAR ,PART_CONTROL_IRQ_MASK ); + pc->closing = false; + pc->last_cmd.aw_id =AW_UNASSIGNED ; + pc->last_cmd.cmd =0 ; +return 0 ; +case PART_STATE_WINDOW_OPENING : + ret =partition_state_wait (pc,PART_STATE_WINDOW_OPEN ); + fallthrough; +case PART_STATE_WINDOW_OPEN : +/* +* Window was left open likely due to arbiter restart. Send +* YIELD_NOW to current AW and wait for it to yield GPU access. +* On timeout, forcibly close the window. +*/ +if (!ret) + ret =yield_now (pc); +else + ret =window_close (pc); + +/* state changed, reevaluate state */ +if (ret == -EAGAIN ) { + ret =0 ; + goto again; + } + fallthrough; +case PART_STATE_WINDOW_CLOSED : + ret =partition_state_wait (pc,PART_STATE_RESET ); + goto again; + } + +return -EINVAL ; +} +static int partition_control_init (struct panthor_arbitration *adev,int i) {struct panthor_partition_control *pc;
@@ -407,6 +456,7 @@ static int partition_control_init(struct panthor_arbitration *adev, int i)spin_lock_init (&pc->irq_lock); pc->irq_suspended = true; +gpu_write (pc->iomem,AM_PART_IRQ_MASK ,0 );spin_lock_init (&pc->lock); pc->current_aw =AW_UNASSIGNED ;
@@ -429,6 +479,10 @@ static int partition_control_init(struct panthor_arbitration *adev, int i) adev->pc[i] = pc; + ret =partition_ensure_reset (pc); +if (ret) +return ret; +partition_irq_resume (pc);return 0 ;
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH v2 28/28] drm/panthor: Reset partitions before starting arbitration
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider: - [Medium] drm/panthor: adev->pc[i] left set on partition_ensure_reset() failure --
Thank you for your contribution! Sashiko AI review found 1 potential issue to consider:
- [Medium] drm/panthor: adev->pc[i] left set on partition_ensure_reset() failure
--
commit 872e2f2e631e5b4428bb12ac09aefb750b611c43
Author: Karunika Choo <[email protected]>
drm/panthor: Reset partitions before starting arbitration
This commit ensures each partition is brought into the RESET state with interrupts masked during partition control initialization before starting arbitration.
Quoted 4 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +0
-0
[ ... ]
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c static int partition_control_init(struct panthor_arbitration *adev, int i) · line 484
Quoted 7 lines
drivers/gpu/drm/panthor/arbitration/panthor_partition_control.c +3
-0@@ -429,6 +479,10 @@ static int partition_control_init(struct panthor_arbitration *adev, int i) adev->pc[i] = pc; + ret =partition_ensure_reset (pc); +if (ret) +return ret;
[Severity: Medium]
Should adev->pc[i] be assigned only after partition_ensure_reset() succeeds?
When partition_ensure_reset() fails, panthor_arbitration_probe() unwinds via panthor_partition_control_term(), which iterates over non-NULL adev->pc[i] entries and runs window_close() and partition_state_wait() on the partition that just failed reset recovery, triggering WARN_ON() and an extra 5-second timeout.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=28