OSDN Git Service

drm/mgag200: Protect concurrent access to I/O registers with lock
authorThomas Zimmermann <tzimmermann@suse.de>
Mon, 2 May 2022 14:25:14 +0000 (16:25 +0200)
committerThomas Zimmermann <tzimmermann@suse.de>
Thu, 5 May 2022 07:18:54 +0000 (09:18 +0200)
Add a mutex lock to protect concurrent access to I/O registers
against each other. This happens between invocation of commit-
tail functions and get-mode operations. Both with use the CRTC
index registers MGA1064_GEN_IO_DATA and MGA1064_GEN_IO_CTL.
Concurrent access can lead to failed mode-setting operations.

v2:
* fix typo in commit description (Jocelyn)
* add comment to explain rmmio_lock

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20220502142514.2174-4-tzimmermann@suse.de
drivers/gpu/drm/mgag200/mgag200_drv.c
drivers/gpu/drm/mgag200/mgag200_drv.h
drivers/gpu/drm/mgag200/mgag200_mode.c

index 217844d..0883946 100644 (file)
@@ -14,6 +14,7 @@
 #include <drm/drm_drv.h>
 #include <drm/drm_file.h>
 #include <drm/drm_ioctl.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_module.h>
 #include <drm/drm_pciids.h>
 
@@ -65,6 +66,11 @@ static int mgag200_regs_init(struct mga_device *mdev)
        struct pci_dev *pdev = to_pci_dev(dev->dev);
        u32 option, option2;
        u8 crtcext3;
+       int ret;
+
+       ret = drmm_mutex_init(dev, &mdev->rmmio_lock);
+       if (ret)
+               return ret;
 
        switch (mdev->type) {
        case G200_PCI:
index 4368112..a18384c 100644 (file)
@@ -213,6 +213,7 @@ struct mga_device {
        struct drm_device               base;
        unsigned long                   flags;
 
+       struct mutex                    rmmio_lock; /* Protects access to rmmio */
        resource_size_t                 rmmio_base;
        resource_size_t                 rmmio_size;
        void __iomem                    *rmmio;
index 6e18d3b..abde765 100644 (file)
@@ -881,6 +881,14 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
                .y2 = fb->height,
        };
 
+       /*
+        * Concurrent operations could possibly trigger a call to
+        * drm_connector_helper_funcs.get_modes by trying to read the
+        * display modes. Protect access to I/O registers by acquiring
+        * the I/O-register lock.
+        */
+       mutex_lock(&mdev->rmmio_lock);
+
        if (mdev->type == G200_WB || mdev->type == G200_EW3)
                mgag200_g200wb_hold_bmc(mdev);
 
@@ -904,6 +912,8 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
        mgag200_enable_display(mdev);
 
        mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]);
+
+       mutex_unlock(&mdev->rmmio_lock);
 }
 
 static void
@@ -963,8 +973,12 @@ mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
        if (!fb)
                return;
 
+       mutex_lock(&mdev->rmmio_lock);
+
        if (drm_atomic_helper_damage_merged(old_state, state, &damage))
                mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]);
+
+       mutex_unlock(&mdev->rmmio_lock);
 }
 
 static struct drm_crtc_state *