Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/fbdev-dma: Only set smem_start is enable per module option

Only export struct fb_info.fix.smem_start if that is required by the
user and the memory does not come from vmalloc().

Setting struct fb_info.fix.smem_start breaks systems where DMA
memory is backed by vmalloc address space. An example error is
shown below.

[ 3.536043] ------------[ cut here ]------------
[ 3.540716] virt_to_phys used for non-linear address: 000000007fc4f540 (0xffff800086001000)
[ 3.552628] WARNING: CPU: 4 PID: 61 at arch/arm64/mm/physaddr.c:12 __virt_to_phys+0x68/0x98
[ 3.565455] Modules linked in:
[ 3.568525] CPU: 4 PID: 61 Comm: kworker/u12:5 Not tainted 6.6.23-06226-g4986cc3e1b75-dirty #250
[ 3.577310] Hardware name: NXP i.MX95 19X19 board (DT)
[ 3.582452] Workqueue: events_unbound deferred_probe_work_func
[ 3.588291] pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 3.595233] pc : __virt_to_phys+0x68/0x98
[ 3.599246] lr : __virt_to_phys+0x68/0x98
[ 3.603276] sp : ffff800083603990
[ 3.677939] Call trace:
[ 3.680393] __virt_to_phys+0x68/0x98
[ 3.684067] drm_fbdev_dma_helper_fb_probe+0x138/0x238
[ 3.689214] __drm_fb_helper_initial_config_and_unlock+0x2b0/0x4c0
[ 3.695385] drm_fb_helper_initial_config+0x4c/0x68
[ 3.700264] drm_fbdev_dma_client_hotplug+0x8c/0xe0
[ 3.705161] drm_client_register+0x60/0xb0
[ 3.709269] drm_fbdev_dma_setup+0x94/0x148

Additionally, DMA memory is assumed to by contiguous in physical
address space, which is not guaranteed by vmalloc().

Resolve this by checking the module flag drm_leak_fbdev_smem when
DRM allocated the instance of struct fb_info. Fbdev-dma then only
sets smem_start only if required (via FBINFO_HIDE_SMEM_START). Also
guarantee that the framebuffer is not located in vmalloc address
space.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reported-by: Peng Fan (OSS) <peng.fan@oss.nxp.com>
Closes: https://lore.kernel.org/dri-devel/20240604080328.4024838-1-peng.fan@oss.nxp.com/
Reported-by: Geert Uytterhoeven <geert+renesas@glider.be>
Closes: https://lore.kernel.org/dri-devel/CAMuHMdX3N0szUvt1VTbroa2zrT1Nye_VzPb5qqCZ7z5gSm7HGw@mail.gmail.com/
Fixes: a51c7663f144 ("drm/fb-helper: Consolidate CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM")
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: <stable@vger.kernel.org> # v6.4+
Link: https://patchwork.freedesktop.org/patch/msgid/20240617152843.11886-1-tzimmermann@suse.de

+7 -4
+3 -3
drivers/gpu/drm/drm_fb_helper.c
··· 524 524 if (!info) 525 525 return ERR_PTR(-ENOMEM); 526 526 527 + if (!drm_leak_fbdev_smem) 528 + info->flags |= FBINFO_HIDE_SMEM_START; 529 + 527 530 ret = fb_alloc_cmap(&info->cmap, 256, 0); 528 531 if (ret) 529 532 goto err_release; ··· 1862 1859 1863 1860 info = fb_helper->info; 1864 1861 info->var.pixclock = 0; 1865 - 1866 - if (!drm_leak_fbdev_smem) 1867 - info->flags |= FBINFO_HIDE_SMEM_START; 1868 1862 1869 1863 /* Need to drop locks to avoid recursive deadlock in 1870 1864 * register_framebuffer. This is ok because the only thing left to do is
+4 -1
drivers/gpu/drm/drm_fbdev_dma.c
··· 130 130 info->flags |= FBINFO_READS_FAST; /* signal caching */ 131 131 info->screen_size = sizes->surface_height * fb->pitches[0]; 132 132 info->screen_buffer = map.vaddr; 133 - info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer)); 133 + if (!(info->flags & FBINFO_HIDE_SMEM_START)) { 134 + if (!drm_WARN_ON(dev, is_vmalloc_addr(info->screen_buffer))) 135 + info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer)); 136 + } 134 137 info->fix.smem_len = info->screen_size; 135 138 136 139 return 0;