drm/drm_fb_helper: fix fbdev with sparc64
authorSam Ravnborg <sam@ravnborg.org>
Thu, 9 Jul 2020 19:30:16 +0000 (21:30 +0200)
committerSam Ravnborg <sam@ravnborg.org>
Mon, 27 Jul 2020 14:47:46 +0000 (16:47 +0200)
Recent kernels have been reported to panic using the bochs_drm
framebuffer under qemu-system-sparc64 which was bisected to
commit 7a0483ac4ffc ("drm/bochs: switch to generic drm fbdev emulation").

The backtrace indicates that the shadow framebuffer copy in
drm_fb_helper_dirty_blit_real() is trying to access the real
framebuffer using a virtual address rather than use an IO access
typically implemented using a physical (ASI_PHYS) access on SPARC.

The fix is to replace the memcpy with memcpy_toio() from io.h.

memcpy_toio() uses writeb() where the original fbdev code
used sbus_memcpy_toio(). The latter uses sbus_writeb().

The difference between writeb() and sbus_memcpy_toio() is
that writeb() writes bytes in little-endian, where sbus_writeb() writes
bytes in big-endian. As endian does not matter for byte writes they are
the same. So we can safely use memcpy_toio() here.

Note that this only fixes bochs, in general fbdev helpers still have
issues with mixing up system memory and __iomem space. Fixing that will
require a lot more work.

v3:
  - Improved changelog (Daniel)
  - Added FIXME to fbdev_use_iomem (Daniel)

v2:
  - Added missing __iomem cast (kernel test robot)
  - Made changelog readable and fix typos (Mark)
  - Add flag to select iomem - and set it in the bochs driver

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Reported-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reported-by: kernel test robot <lkp@intel.com>
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: sparclinux@vger.kernel.org
Link: https://patchwork.freedesktop.org/patch/msgid/20200709193016.291267-1-sam@ravnborg.org
Link: https://patchwork.freedesktop.org/patch/msgid/20200725191012.GA434957@ravnborg.org
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/drm_fb_helper.c
include/drm/drm_mode_config.h

index 05d8373..079f46f 100644 (file)
@@ -146,6 +146,7 @@ int bochs_kms_init(struct bochs_device *bochs)
        bochs->dev->mode_config.preferred_depth = 24;
        bochs->dev->mode_config.prefer_shadow = 0;
        bochs->dev->mode_config.prefer_shadow_fbdev = 1;
+       bochs->dev->mode_config.fbdev_use_iomem = true;
        bochs->dev->mode_config.quirk_addfb_prefer_host_byte_order = true;
 
        bochs->dev->mode_config.funcs = &bochs_mode_funcs;
index 5609e16..89cfd68 100644 (file)
@@ -399,7 +399,11 @@ static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper,
        unsigned int y;
 
        for (y = clip->y1; y < clip->y2; y++) {
-               memcpy(dst, src, len);
+               if (!fb_helper->dev->mode_config.fbdev_use_iomem)
+                       memcpy(dst, src, len);
+               else
+                       memcpy_toio((void __iomem *)dst, src, len);
+
                src += fb->pitches[0];
                dst += fb->pitches[0];
        }
index 6c3ef49..e73dea5 100644 (file)
@@ -866,6 +866,18 @@ struct drm_mode_config {
        bool prefer_shadow_fbdev;
 
        /**
+        * @fbdev_use_iomem:
+        *
+        * Set to true if framebuffer reside in iomem.
+        * When set to true memcpy_toio() is used when copying the framebuffer in
+        * drm_fb_helper.drm_fb_helper_dirty_blit_real().
+        *
+        * FIXME: This should be replaced with a per-mapping is_iomem
+        * flag (like ttm does), and then used everywhere in fbdev code.
+        */
+       bool fbdev_use_iomem;
+
+       /**
         * @quirk_addfb_prefer_xbgr_30bpp:
         *
         * Special hack for legacy ADDFB to keep nouveau userspace happy. Should