--- /dev/null
+From stable+bounces-294132-greg=kroah.com@vger.kernel.org Fri Jul 31 18:07:44 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 31 Jul 2026 12:00:49 -0400
+Subject: drm/amdgpu: Fix context pstate override handling
+To: stable@vger.kernel.org
+Cc: "Tvrtko Ursulin" <tvrtko.ursulin@igalia.com>, "Chengming Gui" <Jack.Gui@amd.com>, "Alex Deucher" <alexander.deucher@amd.com>, "Christian König" <christian.koenig@amd.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260731160049.647545-1-sashal@kernel.org>
+
+From: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+
+[ Upstream commit c1dc4ccb82c9e56325d8e7514ca4c90bd1efb351 ]
+
+There are several problems in the context pstate handling code.
+
+The most serious ones are potential use-after-free and NULL pointer
+dereferences at context initialization time. Both are due
+amdgpu_ctx_init() not holding the adev->pm.stable_pstate_ctx_lock, which
+is otherwise used from both sysfs and the context code itself for
+modifying and clearing the stored context pointer.
+
+Second issue is that context fini can trample over the pstate
+configuration set via sysfs. This is due the restore state
+(ctx->stable_pstate) being saved at context init time, and not if, or when
+the context actually changes the pstate. As the context exits it will
+therefore incorrectly restore to what was set before the sysfs override
+was requested.
+
+The simplest fix is to drastically simplify how the state is tracked, by
+clearly defining the points at which pstate ownership is taken and
+released, and to handle all transitions under the correct lock.
+
+Instead of at context init time, the previous state is saved only at the
+point the context overrides the current state, and is restored on context
+exit only if the context is still the owner of the current override state.
+
+Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
+Fixes: 79610d304133 ("drm/amdgpu: fix pstate setting issue")
+Cc: Chengming Gui <Jack.Gui@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: "Christian König" <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 1b5e413713c0a93bc1818394d0ce49aaad21bd27)
+Cc: <stable@vger.kernel.org> # v6.1+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 71 ++++++++++++++++++--------------
+ 1 file changed, 42 insertions(+), 29 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+@@ -321,7 +321,6 @@ static int amdgpu_ctx_init(struct amdgpu
+ struct drm_file *filp, struct amdgpu_ctx *ctx)
+ {
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+- u32 current_stable_pstate;
+ int r;
+
+ r = amdgpu_ctx_priority_permit(filp, priority);
+@@ -339,37 +338,22 @@ static int amdgpu_ctx_init(struct amdgpu
+ ctx->generation = amdgpu_vm_generation(mgr->adev, &fpriv->vm);
+ ctx->init_priority = priority;
+ ctx->override_priority = AMDGPU_CTX_PRIORITY_UNSET;
+-
+- r = amdgpu_ctx_get_stable_pstate(ctx, ¤t_stable_pstate);
+- if (r)
+- return r;
+-
+- if (mgr->adev->pm.stable_pstate_ctx)
+- ctx->stable_pstate = mgr->adev->pm.stable_pstate_ctx->stable_pstate;
+- else
+- ctx->stable_pstate = current_stable_pstate;
++ ctx->stable_pstate = AMDGPU_CTX_STABLE_PSTATE_NONE;
+
+ ctx->ctx_mgr = &(fpriv->ctx_mgr);
+ return 0;
+ }
+
+-static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
+- u32 stable_pstate)
++static int __amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
++ u32 stable_pstate)
+ {
+ struct amdgpu_device *adev = ctx->mgr->adev;
+ enum amd_dpm_forced_level level;
++ struct amdgpu_ctx *current_ctx;
+ u32 current_stable_pstate;
+- int r;
+-
+- mutex_lock(&adev->pm.stable_pstate_ctx_lock);
+- if (adev->pm.stable_pstate_ctx && adev->pm.stable_pstate_ctx != ctx) {
+- r = -EBUSY;
+- goto done;
+- }
++ int r = 0;
+
+- r = amdgpu_ctx_get_stable_pstate(ctx, ¤t_stable_pstate);
+- if (r || (stable_pstate == current_stable_pstate))
+- goto done;
++ lockdep_assert_held(&adev->pm.stable_pstate_ctx_lock);
+
+ switch (stable_pstate) {
+ case AMDGPU_CTX_STABLE_PSTATE_NONE:
+@@ -388,17 +372,41 @@ static int amdgpu_ctx_set_stable_pstate(
+ level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
+ break;
+ default:
+- r = -EINVAL;
+- goto done;
++ return -EINVAL;
+ }
+
++ current_ctx = adev->pm.stable_pstate_ctx;
++ if (current_ctx && current_ctx != ctx)
++ return -EBUSY;
++
++ r = amdgpu_ctx_get_stable_pstate(ctx, ¤t_stable_pstate);
++ if (r || current_stable_pstate == stable_pstate)
++ return r;
++
+ r = amdgpu_dpm_force_performance_level(adev, level);
++ if (r)
++ return r;
+
+- if (level == AMD_DPM_FORCED_LEVEL_AUTO)
+- adev->pm.stable_pstate_ctx = NULL;
+- else
++ if (!current_ctx) {
+ adev->pm.stable_pstate_ctx = ctx;
+-done:
++ /*
++ * Serialized by context taking ownership for the first time
++ * while holding adev->pm.stable_pstate_ctx_lock).
++ */
++ WRITE_ONCE(ctx->stable_pstate, current_stable_pstate);
++ }
++
++ return 0;
++}
++
++static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
++ u32 stable_pstate)
++{
++ struct amdgpu_device *adev = ctx->mgr->adev;
++ int r;
++
++ mutex_lock(&adev->pm.stable_pstate_ctx_lock);
++ r = __amdgpu_ctx_set_stable_pstate(ctx, stable_pstate);
+ mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
+
+ return r;
+@@ -424,7 +432,12 @@ static void amdgpu_ctx_fini(struct kref
+ }
+
+ if (drm_dev_enter(adev_to_drm(adev), &idx)) {
+- amdgpu_ctx_set_stable_pstate(ctx, ctx->stable_pstate);
++ mutex_lock(&adev->pm.stable_pstate_ctx_lock);
++ if (adev->pm.stable_pstate_ctx == ctx) {
++ __amdgpu_ctx_set_stable_pstate(ctx, ctx->stable_pstate);
++ adev->pm.stable_pstate_ctx = NULL;
++ }
++ mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
+ drm_dev_exit(idx);
+ }
+
--- /dev/null
+From stable+bounces-293912-greg=kroah.com@vger.kernel.org Fri Jul 31 04:41:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 30 Jul 2026 22:41:00 -0400
+Subject: drm/fb-helper: Allocate and release fb_info in single place
+To: stable@vger.kernel.org
+Cc: "Thomas Zimmermann" <tzimmermann@suse.de>, "Christian König" <christian.koenig@amd.com>, "Dmitry Baryshkov" <dmitry.baryshkov@oss.qualcomm.com>, "Javier Martinez Canillas" <javierm@redhat.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20260731024101.3339564-1-sashal@kernel.org>
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit 63c971af40365ee706c7e24f6a7900d693518f09 ]
+
+Move the calls to drm_fb_helper_alloc_info() from drivers into a
+single place in fbdev helpers. Allocates struct fb_info for a new
+framebuffer device. Then call drm_fb_helper_single_fb_probe() to
+create an fbdev screen buffer. Also release the instance on errors
+by calling drm_fb_helper_release_info().
+
+Simplifies the code and fixes the error cleanup for some of the
+drivers.
+
+Regular release of the struct fb_info instance still happens in
+drm_fb_helper_fini() as before.
+
+v2:
+- remove error rollback in driver implementations (kernel test robot)
+- initialize info in TTM implementation (kernel test robot)
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Acked-by: Christian König <christian.koenig@amd.com> # radeon
+Acked-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> # msm
+Acked-by: Javier Martinez Canillas <javierm@redhat.com>
+Link: https://patch.msgid.link/20251027081245.80262-1-tzimmermann@suse.de
+Stable-dep-of: a18b6e30ecd6 ("drm/tegra: fbdev: Remove offset into framebuffer memory")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/armada/armada_fbdev.c | 12 --------
+ drivers/gpu/drm/drm_fb_helper.c | 39 ++++++++---------------------
+ drivers/gpu/drm/drm_fbdev_dma.c | 12 +-------
+ drivers/gpu/drm/drm_fbdev_shmem.c | 12 +-------
+ drivers/gpu/drm/drm_fbdev_ttm.c | 12 +-------
+ drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 9 ------
+ drivers/gpu/drm/gma500/fbdev.c | 12 --------
+ drivers/gpu/drm/i915/display/intel_fbdev.c | 9 ------
+ drivers/gpu/drm/msm/msm_fbdev.c | 9 ------
+ drivers/gpu/drm/omapdrm/omap_fbdev.c | 9 ------
+ drivers/gpu/drm/radeon/radeon_fbdev.c | 13 ---------
+ drivers/gpu/drm/tegra/fbdev.c | 9 ------
+ include/drm/drm_fb_helper.h | 12 --------
+ 13 files changed, 26 insertions(+), 143 deletions(-)
+
+--- a/drivers/gpu/drm/armada/armada_fbdev.c
++++ b/drivers/gpu/drm/armada/armada_fbdev.c
+@@ -45,10 +45,10 @@ int armada_fbdev_driver_fbdev_probe(stru
+ struct drm_fb_helper_surface_size *sizes)
+ {
+ struct drm_device *dev = fbh->dev;
++ struct fb_info *info = fbh->info;
+ struct drm_mode_fb_cmd2 mode;
+ struct armada_framebuffer *dfb;
+ struct armada_gem_object *obj;
+- struct fb_info *info;
+ int size, ret;
+ void *ptr;
+
+@@ -92,12 +92,6 @@ int armada_fbdev_driver_fbdev_probe(stru
+ if (IS_ERR(dfb))
+ return PTR_ERR(dfb);
+
+- info = drm_fb_helper_alloc_info(fbh);
+- if (IS_ERR(info)) {
+- ret = PTR_ERR(info);
+- goto err_fballoc;
+- }
+-
+ info->fbops = &armada_fb_ops;
+ info->fix.smem_start = obj->phys_addr;
+ info->fix.smem_len = obj->obj.size;
+@@ -113,8 +107,4 @@ int armada_fbdev_driver_fbdev_probe(stru
+ (unsigned long long)obj->phys_addr);
+
+ return 0;
+-
+- err_fballoc:
+- dfb->fb.funcs->destroy(&dfb->fb);
+- return ret;
+ }
+--- a/drivers/gpu/drm/drm_fb_helper.c
++++ b/drivers/gpu/drm/drm_fb_helper.c
+@@ -489,20 +489,7 @@ int drm_fb_helper_init(struct drm_device
+ }
+ EXPORT_SYMBOL(drm_fb_helper_init);
+
+-/**
+- * drm_fb_helper_alloc_info - allocate fb_info and some of its members
+- * @fb_helper: driver-allocated fbdev helper
+- *
+- * A helper to alloc fb_info and the member cmap. Called by the driver
+- * within the struct &drm_driver.fbdev_probe callback function. Drivers do
+- * not need to release the allocated fb_info structure themselves, this is
+- * automatically done when calling drm_fb_helper_fini().
+- *
+- * RETURNS:
+- * fb_info pointer if things went okay, pointer containing error code
+- * otherwise
+- */
+-struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)
++static struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)
+ {
+ struct device *dev = fb_helper->dev->dev;
+ struct fb_info *info;
+@@ -529,17 +516,8 @@ err_release:
+ framebuffer_release(info);
+ return ERR_PTR(ret);
+ }
+-EXPORT_SYMBOL(drm_fb_helper_alloc_info);
+
+-/**
+- * drm_fb_helper_release_info - release fb_info and its members
+- * @fb_helper: driver-allocated fbdev helper
+- *
+- * A helper to release fb_info and the member cmap. Drivers do not
+- * need to release the allocated fb_info structure themselves, this is
+- * automatically done when calling drm_fb_helper_fini().
+- */
+-void drm_fb_helper_release_info(struct drm_fb_helper *fb_helper)
++static void drm_fb_helper_release_info(struct drm_fb_helper *fb_helper)
+ {
+ struct fb_info *info = fb_helper->info;
+
+@@ -552,7 +530,6 @@ void drm_fb_helper_release_info(struct d
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+-EXPORT_SYMBOL(drm_fb_helper_release_info);
+
+ /**
+ * drm_fb_helper_unregister_info - unregister fb_info framebuffer device
+@@ -1813,6 +1790,11 @@ __drm_fb_helper_initial_config_and_unloc
+ height = dev->mode_config.max_height;
+
+ drm_client_modeset_probe(&fb_helper->client, width, height);
++
++ info = drm_fb_helper_alloc_info(fb_helper);
++ if (IS_ERR(info))
++ return PTR_ERR(info);
++
+ ret = drm_fb_helper_single_fb_probe(fb_helper);
+ if (ret < 0) {
+ if (ret == -EAGAIN) {
+@@ -1821,13 +1803,12 @@ __drm_fb_helper_initial_config_and_unloc
+ }
+ mutex_unlock(&fb_helper->lock);
+
+- return ret;
++ goto err_drm_fb_helper_release_info;
+ }
+ drm_setup_crtcs_fb(fb_helper);
+
+ fb_helper->deferred_setup = false;
+
+- info = fb_helper->info;
+ info->var.pixclock = 0;
+
+ /* Need to drop locks to avoid recursive deadlock in
+@@ -1850,6 +1831,10 @@ __drm_fb_helper_initial_config_and_unloc
+ mutex_unlock(&kernel_fb_helper_lock);
+
+ return 0;
++
++err_drm_fb_helper_release_info:
++ drm_fb_helper_release_info(fb_helper);
++ return ret;
+ }
+
+ /**
+--- a/drivers/gpu/drm/drm_fbdev_dma.c
++++ b/drivers/gpu/drm/drm_fbdev_dma.c
+@@ -272,9 +272,9 @@ int drm_fbdev_dma_driver_fbdev_probe(str
+ {
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
++ struct fb_info *info = fb_helper->info;
+ struct drm_client_buffer *buffer;
+ struct drm_framebuffer *fb;
+- struct fb_info *info;
+ u32 format;
+ struct iosys_map map;
+ int ret;
+@@ -304,12 +304,6 @@ int drm_fbdev_dma_driver_fbdev_probe(str
+ fb_helper->buffer = buffer;
+ fb_helper->fb = fb;
+
+- info = drm_fb_helper_alloc_info(fb_helper);
+- if (IS_ERR(info)) {
+- ret = PTR_ERR(info);
+- goto err_drm_client_buffer_vunmap;
+- }
+-
+ drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+ if (fb->funcs->dirty)
+@@ -317,12 +311,10 @@ int drm_fbdev_dma_driver_fbdev_probe(str
+ else
+ ret = drm_fbdev_dma_driver_fbdev_probe_tail(fb_helper, sizes);
+ if (ret)
+- goto err_drm_fb_helper_release_info;
++ goto err_drm_client_buffer_vunmap;
+
+ return 0;
+
+-err_drm_fb_helper_release_info:
+- drm_fb_helper_release_info(fb_helper);
+ err_drm_client_buffer_vunmap:
+ fb_helper->fb = NULL;
+ fb_helper->buffer = NULL;
+--- a/drivers/gpu/drm/drm_fbdev_shmem.c
++++ b/drivers/gpu/drm/drm_fbdev_shmem.c
+@@ -136,10 +136,10 @@ int drm_fbdev_shmem_driver_fbdev_probe(s
+ {
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
++ struct fb_info *info = fb_helper->info;
+ struct drm_client_buffer *buffer;
+ struct drm_gem_shmem_object *shmem;
+ struct drm_framebuffer *fb;
+- struct fb_info *info;
+ u32 format;
+ struct iosys_map map;
+ int ret;
+@@ -169,12 +169,6 @@ int drm_fbdev_shmem_driver_fbdev_probe(s
+ fb_helper->buffer = buffer;
+ fb_helper->fb = fb;
+
+- info = drm_fb_helper_alloc_info(fb_helper);
+- if (IS_ERR(info)) {
+- ret = PTR_ERR(info);
+- goto err_drm_client_buffer_vunmap;
+- }
+-
+ drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+ info->fbops = &drm_fbdev_shmem_fb_ops;
+@@ -195,12 +189,10 @@ int drm_fbdev_shmem_driver_fbdev_probe(s
+ info->fbdefio = &fb_helper->fbdefio;
+ ret = fb_deferred_io_init(info);
+ if (ret)
+- goto err_drm_fb_helper_release_info;
++ goto err_drm_client_buffer_vunmap;
+
+ return 0;
+
+-err_drm_fb_helper_release_info:
+- drm_fb_helper_release_info(fb_helper);
+ err_drm_client_buffer_vunmap:
+ fb_helper->fb = NULL;
+ fb_helper->buffer = NULL;
+--- a/drivers/gpu/drm/drm_fbdev_ttm.c
++++ b/drivers/gpu/drm/drm_fbdev_ttm.c
+@@ -176,8 +176,8 @@ int drm_fbdev_ttm_driver_fbdev_probe(str
+ {
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
++ struct fb_info *info = fb_helper->info;
+ struct drm_client_buffer *buffer;
+- struct fb_info *info;
+ size_t screen_size;
+ void *screen_buffer;
+ u32 format;
+@@ -205,12 +205,6 @@ int drm_fbdev_ttm_driver_fbdev_probe(str
+ goto err_drm_client_framebuffer_delete;
+ }
+
+- info = drm_fb_helper_alloc_info(fb_helper);
+- if (IS_ERR(info)) {
+- ret = PTR_ERR(info);
+- goto err_vfree;
+- }
+-
+ drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+ info->fbops = &drm_fbdev_ttm_fb_ops;
+@@ -227,12 +221,10 @@ int drm_fbdev_ttm_driver_fbdev_probe(str
+ info->fbdefio = &fb_helper->fbdefio;
+ ret = fb_deferred_io_init(info);
+ if (ret)
+- goto err_drm_fb_helper_release_info;
++ goto err_vfree;
+
+ return 0;
+
+-err_drm_fb_helper_release_info:
+- drm_fb_helper_release_info(fb_helper);
+ err_vfree:
+ vfree(screen_buffer);
+ err_drm_client_framebuffer_delete:
+--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
++++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+@@ -59,18 +59,11 @@ static int exynos_drm_fbdev_update(struc
+ struct drm_fb_helper_surface_size *sizes,
+ struct exynos_drm_gem *exynos_gem)
+ {
+- struct fb_info *fbi;
++ struct fb_info *fbi = helper->info;
+ struct drm_framebuffer *fb = helper->fb;
+ unsigned int size = fb->width * fb->height * fb->format->cpp[0];
+ unsigned long offset;
+
+- fbi = drm_fb_helper_alloc_info(helper);
+- if (IS_ERR(fbi)) {
+- DRM_DEV_ERROR(to_dma_dev(helper->dev),
+- "failed to allocate fb info.\n");
+- return PTR_ERR(fbi);
+- }
+-
+ fbi->fbops = &exynos_drm_fb_ops;
+
+ drm_fb_helper_fill_info(fbi, helper, sizes);
+--- a/drivers/gpu/drm/gma500/fbdev.c
++++ b/drivers/gpu/drm/gma500/fbdev.c
+@@ -111,7 +111,7 @@ int psb_fbdev_driver_fbdev_probe(struct
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+ struct pci_dev *pdev = to_pci_dev(dev->dev);
+- struct fb_info *info;
++ struct fb_info *info = fb_helper->info;
+ struct drm_framebuffer *fb;
+ struct drm_mode_fb_cmd2 mode_cmd = { };
+ int size;
+@@ -170,12 +170,6 @@ int psb_fbdev_driver_fbdev_probe(struct
+ fb_helper->funcs = &psb_fbdev_fb_helper_funcs;
+ fb_helper->fb = fb;
+
+- info = drm_fb_helper_alloc_info(fb_helper);
+- if (IS_ERR(info)) {
+- ret = PTR_ERR(info);
+- goto err_drm_framebuffer_unregister_private;
+- }
+-
+ info->fbops = &psb_fbdev_fb_ops;
+
+ /* Accessed stolen memory directly */
+@@ -199,10 +193,6 @@ int psb_fbdev_driver_fbdev_probe(struct
+
+ return 0;
+
+-err_drm_framebuffer_unregister_private:
+- drm_framebuffer_unregister_private(fb);
+- drm_framebuffer_cleanup(fb);
+- kfree(fb);
+ err_drm_gem_object_put:
+ drm_gem_object_put(obj);
+ return ret;
+--- a/drivers/gpu/drm/i915/display/intel_fbdev.c
++++ b/drivers/gpu/drm/i915/display/intel_fbdev.c
+@@ -242,8 +242,8 @@ int intel_fbdev_driver_fbdev_probe(struc
+ struct intel_display *display = to_intel_display(helper->dev);
+ struct intel_fbdev *ifbdev = to_intel_fbdev(helper);
+ struct intel_framebuffer *fb = ifbdev->fb;
++ struct fb_info *info = helper->info;
+ struct ref_tracker *wakeref;
+- struct fb_info *info;
+ struct i915_vma *vma;
+ unsigned long flags = 0;
+ bool prealloc = false;
+@@ -296,13 +296,6 @@ int intel_fbdev_driver_fbdev_probe(struc
+ goto out_unlock;
+ }
+
+- info = drm_fb_helper_alloc_info(helper);
+- if (IS_ERR(info)) {
+- drm_err(display->drm, "Failed to allocate fb_info (%pe)\n", info);
+- ret = PTR_ERR(info);
+- goto out_unpin;
+- }
+-
+ helper->funcs = &intel_fb_helper_funcs;
+ helper->fb = &fb->base;
+
+--- a/drivers/gpu/drm/msm/msm_fbdev.c
++++ b/drivers/gpu/drm/msm/msm_fbdev.c
+@@ -93,9 +93,9 @@ int msm_fbdev_driver_fbdev_probe(struct
+ {
+ struct drm_device *dev = helper->dev;
+ struct msm_drm_private *priv = dev->dev_private;
++ struct fb_info *fbi = helper->info;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_gem_object *bo;
+- struct fb_info *fbi = NULL;
+ uint64_t paddr;
+ uint32_t format;
+ int ret, pitch;
+@@ -128,13 +128,6 @@ int msm_fbdev_driver_fbdev_probe(struct
+ goto fail;
+ }
+
+- fbi = drm_fb_helper_alloc_info(helper);
+- if (IS_ERR(fbi)) {
+- DRM_DEV_ERROR(dev->dev, "failed to allocate fb info\n");
+- ret = PTR_ERR(fbi);
+- goto fail;
+- }
+-
+ DBG("fbi=%p, dev=%p", fbi, dev);
+
+ helper->funcs = &msm_fbdev_helper_funcs;
+--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
++++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
+@@ -155,9 +155,9 @@ int omap_fbdev_driver_fbdev_probe(struct
+ struct drm_device *dev = helper->dev;
+ struct omap_drm_private *priv = dev->dev_private;
+ struct omap_fbdev *fbdev = priv->fbdev;
++ struct fb_info *fbi = helper->info;
+ struct drm_framebuffer *fb = NULL;
+ union omap_gem_size gsize;
+- struct fb_info *fbi = NULL;
+ struct drm_mode_fb_cmd2 mode_cmd = {0};
+ struct drm_gem_object *bo;
+ dma_addr_t dma_addr;
+@@ -226,13 +226,6 @@ int omap_fbdev_driver_fbdev_probe(struct
+ goto fail;
+ }
+
+- fbi = drm_fb_helper_alloc_info(helper);
+- if (IS_ERR(fbi)) {
+- dev_err(dev->dev, "failed to allocate fb info\n");
+- ret = PTR_ERR(fbi);
+- goto fail;
+- }
+-
+ DBG("fbi=%p, dev=%p", fbi, dev);
+
+ helper->funcs = &omap_fbdev_helper_funcs;
+--- a/drivers/gpu/drm/radeon/radeon_fbdev.c
++++ b/drivers/gpu/drm/radeon/radeon_fbdev.c
+@@ -206,7 +206,7 @@ int radeon_fbdev_driver_fbdev_probe(stru
+ struct radeon_device *rdev = fb_helper->dev->dev_private;
+ const struct drm_format_info *format_info;
+ struct drm_mode_fb_cmd2 mode_cmd = { };
+- struct fb_info *info;
++ struct fb_info *info = fb_helper->info;
+ struct drm_gem_object *gobj;
+ struct radeon_bo *rbo;
+ struct drm_framebuffer *fb;
+@@ -247,13 +247,6 @@ int radeon_fbdev_driver_fbdev_probe(stru
+ fb_helper->funcs = &radeon_fbdev_fb_helper_funcs;
+ fb_helper->fb = fb;
+
+- /* okay we have an object now allocate the framebuffer */
+- info = drm_fb_helper_alloc_info(fb_helper);
+- if (IS_ERR(info)) {
+- ret = PTR_ERR(info);
+- goto err_drm_framebuffer_unregister_private;
+- }
+-
+ info->fbops = &radeon_fbdev_fb_ops;
+
+ /* radeon resume is fragile and needs a vt switch to help it along */
+@@ -279,10 +272,6 @@ int radeon_fbdev_driver_fbdev_probe(stru
+
+ return 0;
+
+-err_drm_framebuffer_unregister_private:
+- fb_helper->fb = NULL;
+- drm_framebuffer_unregister_private(fb);
+- drm_framebuffer_cleanup(fb);
+ err_kfree:
+ kfree(fb);
+ err_radeon_fbdev_destroy_pinned_object:
+--- a/drivers/gpu/drm/tegra/fbdev.c
++++ b/drivers/gpu/drm/tegra/fbdev.c
+@@ -75,10 +75,10 @@ int tegra_fbdev_driver_fbdev_probe(struc
+ struct tegra_drm *tegra = helper->dev->dev_private;
+ struct drm_device *drm = helper->dev;
+ struct drm_mode_fb_cmd2 cmd = { 0 };
++ struct fb_info *info = helper->info;
+ unsigned int bytes_per_pixel;
+ struct drm_framebuffer *fb;
+ unsigned long offset;
+- struct fb_info *info;
+ struct tegra_bo *bo;
+ size_t size;
+ int err;
+@@ -99,13 +99,6 @@ int tegra_fbdev_driver_fbdev_probe(struc
+ if (IS_ERR(bo))
+ return PTR_ERR(bo);
+
+- info = drm_fb_helper_alloc_info(helper);
+- if (IS_ERR(info)) {
+- dev_err(drm->dev, "failed to allocate framebuffer info\n");
+- drm_gem_object_put(&bo->gem);
+- return PTR_ERR(info);
+- }
+-
+ fb = tegra_fb_alloc(drm,
+ drm_get_format_info(drm, cmd.pixel_format, cmd.modifier[0]),
+ &cmd, &bo, 1);
+--- a/include/drm/drm_fb_helper.h
++++ b/include/drm/drm_fb_helper.h
+@@ -256,8 +256,6 @@ int drm_fb_helper_check_var(struct fb_va
+
+ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper);
+
+-struct fb_info *drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper);
+-void drm_fb_helper_release_info(struct drm_fb_helper *fb_helper);
+ void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper);
+ void drm_fb_helper_fill_info(struct fb_info *info,
+ struct drm_fb_helper *fb_helper,
+@@ -340,16 +338,6 @@ drm_fb_helper_restore_fbdev_mode_unlocke
+ return 0;
+ }
+
+-static inline struct fb_info *
+-drm_fb_helper_alloc_info(struct drm_fb_helper *fb_helper)
+-{
+- return NULL;
+-}
+-
+-static inline void drm_fb_helper_release_info(struct drm_fb_helper *fb_helper)
+-{
+-}
+-
+ static inline void drm_fb_helper_unregister_info(struct drm_fb_helper *fb_helper)
+ {
+ }