Commit 931e3f3a authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

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: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarJocelyn Falempe <jfalempe@redhat.com>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20220502142514.2174-4-tzimmermann@suse.de
parent f870231f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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:
+1 −0
Original line number Diff line number Diff line
@@ -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;
+14 −0
Original line number Diff line number Diff line
@@ -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 *