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

drm/mgag200: Protect concurrent access to I/O registers with lock

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

+21
+6
drivers/gpu/drm/mgag200/mgag200_drv.c
··· 14 14 #include <drm/drm_drv.h> 15 15 #include <drm/drm_file.h> 16 16 #include <drm/drm_ioctl.h> 17 + #include <drm/drm_managed.h> 17 18 #include <drm/drm_module.h> 18 19 #include <drm/drm_pciids.h> 19 20 ··· 66 65 struct pci_dev *pdev = to_pci_dev(dev->dev); 67 66 u32 option, option2; 68 67 u8 crtcext3; 68 + int ret; 69 + 70 + ret = drmm_mutex_init(dev, &mdev->rmmio_lock); 71 + if (ret) 72 + return ret; 69 73 70 74 switch (mdev->type) { 71 75 case G200_PCI:
+1
drivers/gpu/drm/mgag200/mgag200_drv.h
··· 213 213 struct drm_device base; 214 214 unsigned long flags; 215 215 216 + struct mutex rmmio_lock; /* Protects access to rmmio */ 216 217 resource_size_t rmmio_base; 217 218 resource_size_t rmmio_size; 218 219 void __iomem *rmmio;
+14
drivers/gpu/drm/mgag200/mgag200_mode.c
··· 881 881 .y2 = fb->height, 882 882 }; 883 883 884 + /* 885 + * Concurrent operations could possibly trigger a call to 886 + * drm_connector_helper_funcs.get_modes by trying to read the 887 + * display modes. Protect access to I/O registers by acquiring 888 + * the I/O-register lock. 889 + */ 890 + mutex_lock(&mdev->rmmio_lock); 891 + 884 892 if (mdev->type == G200_WB || mdev->type == G200_EW3) 885 893 mgag200_g200wb_hold_bmc(mdev); 886 894 ··· 912 904 mgag200_enable_display(mdev); 913 905 914 906 mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]); 907 + 908 + mutex_unlock(&mdev->rmmio_lock); 915 909 } 916 910 917 911 static void ··· 973 963 if (!fb) 974 964 return; 975 965 966 + mutex_lock(&mdev->rmmio_lock); 967 + 976 968 if (drm_atomic_helper_damage_merged(old_state, state, &damage)) 977 969 mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]); 970 + 971 + mutex_unlock(&mdev->rmmio_lock); 978 972 } 979 973 980 974 static struct drm_crtc_state *