From b13044092c1e30453d2f7e9be596d3a2616582a0 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Tue, 20 May 2025 15:08:59 -0400 Subject: drm/msm: Temporarily disable stall-on-fault after a page fault When things go wrong, the GPU is capable of quickly generating millions of faulting translation requests per second. When that happens, in the stall-on-fault model each access will stall until it wins the race to signal the fault and then the RESUME register is written. This slows processing page faults to a crawl as the GPU can generate faults much faster than the CPU can acknowledge them. It also means that all available resources in the SMMU are saturated waiting for the stalled transactions, so that other transactions such as transactions generated by the GMU, which shares translation resources with the GPU, cannot proceed. This causes a GMU watchdog timeout, which leads to a failed reset because GX cannot collapse when there is a transaction pending and a permanently hung GPU. On older platforms with qcom,smmu-v2, it seems that when one transaction is stalled subsequent faulting transactions are terminated, which avoids this problem, but the MMU-500 follows the spec here. To work around these problems, disable stall-on-fault as soon as we get a page fault until a cooldown period after pagefaults stop. This allows the GMU some guaranteed time to continue working. We only use stall-on-fault to halt the GPU while we collect a devcoredump and we always terminate the transaction afterward, so it's fine to miss some subsequent page faults. We also keep it disabled so long as the current devcoredump hasn't been deleted, because in that case we likely won't capture another one if there's a fault. After this commit HFI messages still occasionally time out, because the crashdump handler doesn't run fast enough to let the GMU resume, but the driver seems to recover from it. This will probably go away after the HFI timeout is increased. Signed-off-by: Connor Abbott Reviewed-by: Rob Clark Patchwork: https://patchwork.freedesktop.org/patch/654891/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_debugfs.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/gpu/drm/msm/msm_debugfs.c') diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 7ab607252d18..6af72162cda4 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -208,6 +208,35 @@ DEFINE_DEBUGFS_ATTRIBUTE(shrink_fops, shrink_get, shrink_set, "0x%08llx\n"); +/* + * Return the number of microseconds to wait until stall-on-fault is + * re-enabled. If 0 then it is already enabled or will be re-enabled on the + * next submit (unless there's a leftover devcoredump). This is useful for + * kernel tests that intentionally produce a fault and check the devcoredump to + * wait until the cooldown period is over. + */ + +static int +stall_reenable_time_get(void *data, u64 *val) +{ + struct msm_drm_private *priv = data; + unsigned long irq_flags; + + spin_lock_irqsave(&priv->fault_stall_lock, irq_flags); + + if (priv->stall_enabled) + *val = 0; + else + *val = max(ktime_us_delta(priv->stall_reenable_time, ktime_get()), 0); + + spin_unlock_irqrestore(&priv->fault_stall_lock, irq_flags); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(stall_reenable_time_fops, + stall_reenable_time_get, NULL, + "%lld\n"); static int msm_gem_show(struct seq_file *m, void *arg) { @@ -319,6 +348,9 @@ static void msm_debugfs_gpu_init(struct drm_minor *minor) debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root, &priv->disable_err_irq); + debugfs_create_file("stall_reenable_time_us", 0400, minor->debugfs_root, + priv, &stall_reenable_time_fops); + gpu_devfreq = debugfs_create_dir("devfreq", minor->debugfs_root); debugfs_create_bool("idle_clamp",0600, gpu_devfreq, -- cgit v1.2.3 From 98290b0a7d605431480e63ccdb6a118a21a0866c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 5 Jul 2025 13:02:31 +0300 Subject: drm/msm: make it possible to disable KMS-related code. If the Adreno device is used in a headless mode, there is no need to build all KMS components. Build corresponding parts conditionally, only selecting them if modeset support is actually required. Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/662581/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Kconfig | 14 +++++ drivers/gpu/drm/msm/Makefile | 19 +++---- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 4 +- drivers/gpu/drm/msm/dp/dp_debug.c | 4 ++ drivers/gpu/drm/msm/msm_debugfs.c | 92 ++++++++++++++++++-------------- drivers/gpu/drm/msm/msm_drv.h | 10 +--- drivers/gpu/drm/msm/msm_kms.c | 6 +-- drivers/gpu/drm/msm/msm_kms.h | 30 +++++++++++ 8 files changed, 117 insertions(+), 62 deletions(-) (limited to 'drivers/gpu/drm/msm/msm_debugfs.c') diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 8fb99f64a615..3a0a69f41153 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -68,6 +68,14 @@ config DRM_MSM_VALIDATE_XML Validate XML files with register definitions against rules-fd schema. This option is mostly targeting DRM MSM developers. If unsure, say N. +config DRM_MSM_KMS + def_bool n + depends on DRM_MSM + +config DRM_MSM_KMS_FBDEV + def_bool DRM_FBDEV_EMULATION + depends on DRM_MSM_KMS + config DRM_MSM_MDSS bool depends on DRM_MSM @@ -76,6 +84,7 @@ config DRM_MSM_MDSS config DRM_MSM_MDP4 bool "Enable MDP4 support in MSM DRM driver" depends on DRM_MSM + select DRM_MSM_KMS default y help Compile in support for the Mobile Display Processor v4 (MDP4) in @@ -86,6 +95,7 @@ config DRM_MSM_MDP5 bool "Enable MDP5 support in MSM DRM driver" depends on DRM_MSM select DRM_MSM_MDSS + select DRM_MSM_KMS default y help Compile in support for the Mobile Display Processor v5 (MDP5) in @@ -96,6 +106,7 @@ config DRM_MSM_DPU bool "Enable DPU support in MSM DRM driver" depends on DRM_MSM select DRM_MSM_MDSS + select DRM_MSM_KMS select DRM_DISPLAY_DSC_HELPER default y help @@ -106,6 +117,7 @@ config DRM_MSM_DPU config DRM_MSM_DP bool "Enable DisplayPort support in MSM DRM driver" depends on DRM_MSM + depends on DRM_MSM_KMS select DRM_DISPLAY_HDMI_AUDIO_HELPER select RATIONAL default y @@ -117,6 +129,7 @@ config DRM_MSM_DP config DRM_MSM_DSI bool "Enable DSI support in MSM DRM driver" depends on DRM_MSM + depends on DRM_MSM_KMS select DRM_PANEL select DRM_MIPI_DSI select DRM_DISPLAY_DSC_HELPER @@ -172,6 +185,7 @@ config DRM_MSM_DSI_7NM_PHY config DRM_MSM_HDMI bool "Enable HDMI support in MSM DRM driver" depends on DRM_MSM + depends on DRM_MSM_KMS default y select DRM_DISPLAY_HDMI_HELPER select DRM_DISPLAY_HDMI_STATE_HELPER diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 514bacd5e499..0c0dfb25f01b 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -100,18 +100,15 @@ msm-display-$(CONFIG_DRM_MSM_DPU) += \ msm-display-$(CONFIG_DRM_MSM_MDSS) += \ msm_mdss.o \ -msm-display-y += \ +msm-display-$(CONFIG_DRM_MSM_KMS) += \ disp/mdp_format.o \ disp/mdp_kms.o \ disp/msm_disp_snapshot.o \ disp/msm_disp_snapshot_util.o \ msm-y += \ - msm_atomic.o \ - msm_atomic_tracepoints.o \ msm_debugfs.o \ msm_drv.o \ - msm_fb.o \ msm_fence.o \ msm_gem.o \ msm_gem_prime.o \ @@ -122,7 +119,6 @@ msm-y += \ msm_gpu_devfreq.o \ msm_io_utils.o \ msm_iommu.o \ - msm_kms.o \ msm_perf.o \ msm_rd.o \ msm_ringbuffer.o \ @@ -130,13 +126,17 @@ msm-y += \ msm_syncobj.o \ msm_gpu_tracepoints.o \ -msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o +msm-$(CONFIG_DRM_MSM_KMS) += \ + msm_atomic.o \ + msm_atomic_tracepoints.o \ + msm_fb.o \ + msm_kms.o \ -msm-display-$(CONFIG_DEBUG_FS) += \ - dp/dp_debug.o +msm-$(CONFIG_DRM_MSM_KMS_FBDEV) += msm_fbdev.o msm-display-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \ dp/dp_ctrl.o \ + dp/dp_debug.o \ dp/dp_display.o \ dp/dp_drm.o \ dp/dp_link.o \ @@ -159,7 +159,8 @@ msm-display-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/phy/dsi_phy_14nm.o msm-display-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/phy/dsi_phy_10nm.o msm-display-$(CONFIG_DRM_MSM_DSI_7NM_PHY) += dsi/phy/dsi_phy_7nm.o -msm-y += $(adreno-y) $(msm-display-y) +msm-y += $(adreno-y) +msm-$(CONFIG_DRM_MSM_KMS) += $(msm-display-y) obj-$(CONFIG_DRM_MSM) += msm.o diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 782aa86208d5..d4b545448d74 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -742,7 +742,7 @@ void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event) fevent->event = event; fevent->crtc = crtc; fevent->ts = ktime_get(); - kthread_queue_work(priv->event_thread[crtc_id].worker, &fevent->work); + kthread_queue_work(priv->kms->event_thread[crtc_id].worker, &fevent->work); } /** @@ -911,7 +911,7 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc, dev = crtc->dev; priv = dev->dev_private; - if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { + if (crtc->index >= ARRAY_SIZE(priv->kms->event_thread)) { DPU_ERROR("invalid crtc index[%d]\n", crtc->index); return; } diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index b65b358e9838..cf3838fcd154 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -5,6 +5,8 @@ #define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__ +#ifdef CONFIG_DEBUG_FS + #include #include #include @@ -234,3 +236,5 @@ int msm_dp_debug_init(struct device *dev, struct msm_dp_panel *panel, return 0; } + +#endif diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 6af72162cda4..4680ccf3e72f 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -117,6 +117,36 @@ static const struct file_operations msm_gpu_fops = { .release = msm_gpu_release, }; +#ifdef CONFIG_DRM_MSM_KMS +static int msm_fb_show(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_framebuffer *fb, *fbdev_fb = NULL; + + if (dev->fb_helper && dev->fb_helper->fb) { + seq_puts(m, "fbcon "); + fbdev_fb = dev->fb_helper->fb; + msm_framebuffer_describe(fbdev_fb, m); + } + + mutex_lock(&dev->mode_config.fb_lock); + list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + if (fb == fbdev_fb) + continue; + + seq_puts(m, "user "); + msm_framebuffer_describe(fb, m); + } + mutex_unlock(&dev->mode_config.fb_lock); + + return 0; +} + +static struct drm_info_list msm_kms_debugfs_list[] = { + { "fb", msm_fb_show }, +}; + /* * Display Snapshot: */ @@ -180,6 +210,27 @@ static const struct file_operations msm_kms_fops = { .release = msm_kms_release, }; +static void msm_debugfs_kms_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; + + drm_debugfs_create_files(msm_kms_debugfs_list, + ARRAY_SIZE(msm_kms_debugfs_list), + minor->debugfs_root, minor); + debugfs_create_file("kms", 0400, minor->debugfs_root, + dev, &msm_kms_fops); + + if (priv->kms->funcs->debugfs_init) + priv->kms->funcs->debugfs_init(priv->kms, minor); + +} +#else /* ! CONFIG_DRM_MSM_KMS */ +static void msm_debugfs_kms_init(struct drm_minor *minor) +{ +} +#endif + /* * Other debugfs: */ @@ -267,40 +318,11 @@ static int msm_mm_show(struct seq_file *m, void *arg) return 0; } -static int msm_fb_show(struct seq_file *m, void *arg) -{ - struct drm_info_node *node = m->private; - struct drm_device *dev = node->minor->dev; - struct drm_framebuffer *fb, *fbdev_fb = NULL; - - if (dev->fb_helper && dev->fb_helper->fb) { - seq_printf(m, "fbcon "); - fbdev_fb = dev->fb_helper->fb; - msm_framebuffer_describe(fbdev_fb, m); - } - - mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (fb == fbdev_fb) - continue; - - seq_printf(m, "user "); - msm_framebuffer_describe(fb, m); - } - mutex_unlock(&dev->mode_config.fb_lock); - - return 0; -} - static struct drm_info_list msm_debugfs_list[] = { {"gem", msm_gem_show}, { "mm", msm_mm_show }, }; -static struct drm_info_list msm_kms_debugfs_list[] = { - { "fb", msm_fb_show }, -}; - static int late_init_minor(struct drm_minor *minor) { int ret; @@ -375,20 +397,12 @@ void msm_debugfs_init(struct drm_minor *minor) if (priv->gpu_pdev) msm_debugfs_gpu_init(minor); - if (priv->kms) { - drm_debugfs_create_files(msm_kms_debugfs_list, - ARRAY_SIZE(msm_kms_debugfs_list), - minor->debugfs_root, minor); - debugfs_create_file("kms", S_IRUSR, minor->debugfs_root, - dev, &msm_kms_fops); - } + if (priv->kms) + msm_debugfs_kms_init(minor); debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, dev, &shrink_fops); - if (priv->kms && priv->kms->funcs->debugfs_init) - priv->kms->funcs->debugfs_init(priv->kms, minor); - fault_create_debugfs_attr("fail_gem_alloc", minor->debugfs_root, &fail_gem_alloc); fault_create_debugfs_attr("fail_gem_iova", minor->debugfs_root, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index e7872b752c6c..5b276a454075 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -70,12 +70,6 @@ enum msm_dsi_controller { #define MSM_GPU_MAX_RINGS 4 -/* Commit/Event thread specific structure */ -struct msm_drm_thread { - struct drm_device *dev; - struct kthread_worker *worker; -}; - struct msm_drm_private { struct drm_device *dev; @@ -165,8 +159,6 @@ struct msm_drm_private { struct mutex lock; } lru; - struct msm_drm_thread event_thread[MAX_CRTCS]; - struct notifier_block vmap_notifier; struct shrinker *shrinker; @@ -272,7 +264,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format); -#ifdef CONFIG_DRM_FBDEV_EMULATION +#ifdef CONFIG_DRM_MSM_KMS_FBDEV int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes); #define MSM_FBDEV_DRIVER_OPS \ diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c index a63d014c1903..6889f1c1e721 100644 --- a/drivers/gpu/drm/msm/msm_kms.c +++ b/drivers/gpu/drm/msm/msm_kms.c @@ -246,8 +246,8 @@ void msm_drm_kms_uninit(struct device *dev) /* clean up event worker threads */ for (i = 0; i < MAX_CRTCS; i++) { - if (priv->event_thread[i].worker) - kthread_destroy_worker(priv->event_thread[i].worker); + if (kms->event_thread[i].worker) + kthread_destroy_worker(kms->event_thread[i].worker); } drm_kms_helper_poll_fini(ddev); @@ -300,7 +300,7 @@ int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv) struct msm_drm_thread *ev_thread; /* initialize event thread */ - ev_thread = &priv->event_thread[drm_crtc_index(crtc)]; + ev_thread = &kms->event_thread[drm_crtc_index(crtc)]; ev_thread->dev = ddev; ev_thread->worker = kthread_run_worker(0, "crtc_event:%d", crtc->base.id); if (IS_ERR(ev_thread->worker)) { diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index f4eb48653189..8a7be7b854de 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -13,6 +13,8 @@ #include "msm_drv.h" +#ifdef CONFIG_DRM_MSM_KMS + #define MAX_PLANE 4 /* As there are different display controller blocks depending on the @@ -127,6 +129,12 @@ struct msm_pending_timer { unsigned crtc_idx; }; +/* Commit/Event thread specific structure */ +struct msm_drm_thread { + struct drm_device *dev; + struct kthread_worker *worker; +}; + struct msm_kms { const struct msm_kms_funcs *funcs; struct drm_device *dev; @@ -161,6 +169,7 @@ struct msm_kms { struct msm_pending_timer pending_timers[MAX_CRTCS]; struct workqueue_struct *wq; + struct msm_drm_thread event_thread[MAX_CRTCS]; }; static inline int msm_kms_init(struct msm_kms *kms, @@ -210,4 +219,25 @@ void msm_drm_kms_post_init(struct device *dev); void msm_drm_kms_unregister(struct device *dev); void msm_drm_kms_uninit(struct device *dev); +#else /* ! CONFIG_DRM_MSM_KMS */ + +static inline int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv) +{ + return -ENODEV; +} + +static inline void msm_drm_kms_post_init(struct device *dev) +{ +} + +static inline void msm_drm_kms_unregister(struct device *dev) +{ +} + +static inline void msm_drm_kms_uninit(struct device *dev) +{ +} + +#endif + #endif /* __MSM_KMS_H__ */ -- cgit v1.2.3 From 4f89cf40d01ee26fb7eb50f65bae53daf4c3f569 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 5 Jul 2025 13:02:32 +0300 Subject: drm/msm: bail out late_init_minor() if it is not a GPU device Both perf and hangrd make sense only for GPU devices. Bail out if we are registering a KMS-only device. Signed-off-by: Dmitry Baryshkov Patchwork: https://patchwork.freedesktop.org/patch/662583/ Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_debugfs.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/gpu/drm/msm/msm_debugfs.c') diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 4680ccf3e72f..bbda865addae 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -325,11 +325,16 @@ static struct drm_info_list msm_debugfs_list[] = { static int late_init_minor(struct drm_minor *minor) { + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; int ret; if (!minor) return 0; + if (!priv->gpu_pdev) + return 0; + ret = msm_rd_debugfs_init(minor); if (ret) { DRM_DEV_ERROR(minor->dev->dev, "could not install rd debugfs\n"); -- cgit v1.2.3