diff mbox

[05/11] vga_switcheroo: Lock/unlock DDC lines

Message ID 0d2a7e394cd1fd9a0489d5d4ed8c70250c3f0f93.1429610300.git.lukas@wunner.de (mailing list archive)
State New, archived
Headers show

Commit Message

Lukas Wunner Dec. 22, 2012, 2:52 a.m. UTC
From: Dave Airlie <airlied@gmail.com>

Replace vga_switcheroo_switch_ddc() with vga_switcheroo_lock_ddc()
and vga_switcheroo_unlock_ddc(), move mutex from drm_get_edid() to
vga_switcheroo.c

Motivation for these changes according to Dave Airlie:
"I can't figure out why I didn't like this, but I rewrote this way
back to lock/unlock the ddc lines, bits are contained in this WIP
mess. I think I'd prefer something like that otherwise the interface
got really ugly."
http://lists.freedesktop.org/archives/dri-devel/2014-June/061629.html

Original commit by Dave Airlie contained additional experimental
and unused code. Reduced to the bare minimum and amended with this
commit message by Lukas Wunner <lukas@wunner.de>

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/gpu/drm/drm_edid.c       | 16 ++------------
 drivers/gpu/vga/vga_switcheroo.c | 46 ++++++++++++++++++++++++++++++++++++++--
 include/linux/vga_switcheroo.h   |  3 ++-
 3 files changed, 48 insertions(+), 17 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index f208bb3..f91593b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -88,8 +88,6 @@  struct detailed_mode_closure {
 #define LEVEL_GTF2	2
 #define LEVEL_CVT	3
 
-static DEFINE_MUTEX(drm_edid_mutex);
-
 static struct edid_quirk {
 	char vendor[4];
 	int product_id;
@@ -1328,16 +1326,8 @@  struct edid *drm_get_edid(struct drm_connector *connector,
 			  struct i2c_adapter *adapter)
 {
 	struct edid *edid;
-	struct pci_dev *pdev = connector->dev->pdev;
-	struct pci_dev *active_pdev = NULL;
-
-	mutex_lock(&drm_edid_mutex);
 
-	if (pdev) {
-		active_pdev = vga_switcheroo_get_active_client();
-		if (active_pdev != pdev)
-			vga_switcheroo_switch_ddc(pdev);
-	}
+	vga_switcheroo_lock_ddc(connector->dev->pdev);
 
 	if (!drm_probe_ddc(adapter))
 		return NULL;
@@ -1346,10 +1336,8 @@  struct edid *drm_get_edid(struct drm_connector *connector,
 	if (edid)
 		drm_get_displayid(connector, edid);
 
-	if (active_pdev && active_pdev != pdev)
-		vga_switcheroo_switch_ddc(active_pdev);
+	vga_switcheroo_unlock_ddc(connector->dev->pdev);
 
-	mutex_unlock(&drm_edid_mutex);
 	return edid;
 }
 EXPORT_SYMBOL(drm_get_edid);
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 620c4ac..0223020 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -57,6 +57,9 @@  struct vgasr_priv {
 	struct list_head clients;
 
 	struct vga_switcheroo_handler *handler;
+
+	struct mutex ddc_lock;
+	struct pci_dev *old_ddc_owner;
 };
 
 #define ID_BIT_AUDIO		0x100
@@ -70,6 +73,7 @@  static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
 /* only one switcheroo per system */
 static struct vgasr_priv vgasr_priv = {
 	.clients = LIST_HEAD_INIT(vgasr_priv.clients),
+	.ddc_lock = __MUTEX_INITIALIZER(vgasr_priv.ddc_lock),
 };
 
 static bool vga_switcheroo_ready(void)
@@ -270,8 +274,9 @@  void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
 }
 EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
 
-int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
 {
+	struct vga_switcheroo_client *client;
 	int ret = 0;
 	int id;
 
@@ -283,6 +288,18 @@  int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
 	}
 
 	if (vgasr_priv.handler->switch_ddc) {
+		mutex_lock(&vgasr_priv.ddc_lock);
+
+		client = find_active_client(&vgasr_priv.clients);
+		if (!client) {
+			mutex_unlock(&vgasr_priv.ddc_lock);
+			ret = -ENODEV;
+			goto out;
+		}
+		vgasr_priv.old_ddc_owner = client->pdev;
+		if (client->pdev == pdev)
+			goto out;
+
 		id = vgasr_priv.handler->get_client_id(pdev);
 		ret = vgasr_priv.handler->switch_ddc(id);
 	}
@@ -291,7 +308,32 @@  out:
 	mutex_unlock(&vgasr_mutex);
 	return ret;
 }
-EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+EXPORT_SYMBOL(vga_switcheroo_lock_ddc);
+
+int vga_switcheroo_unlock_ddc(struct pci_dev *pdev)
+{
+	int ret = 0;
+	int id;
+	mutex_lock(&vgasr_mutex);
+
+	if (!vgasr_priv.handler) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (vgasr_priv.handler->switch_ddc) {
+		if (vgasr_priv.old_ddc_owner != pdev) {
+			id = vgasr_priv.handler->get_client_id(vgasr_priv.old_ddc_owner);
+			ret = vgasr_priv.handler->switch_ddc(id);
+		}
+		vgasr_priv.old_ddc_owner = NULL;
+		mutex_unlock(&vgasr_priv.ddc_lock);
+	}
+out:
+	mutex_unlock(&vgasr_mutex);
+	return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_unlock_ddc);
 
 static int vga_switcheroo_show(struct seq_file *m, void *v)
 {
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index c81a686..352bef3 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -55,7 +55,8 @@  int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
 void vga_switcheroo_client_fb_set(struct pci_dev *dev,
 				  struct fb_info *info);
 
-int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
+int vga_switcheroo_lock_ddc(struct pci_dev *pdev);
+int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
 
 int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
 void vga_switcheroo_unregister_handler(void);