From: Dave Airlie <airl...@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 at wunner.de>

Signed-off-by: Lukas Wunner <lukas at 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 --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);
-- 
1.8.5.2 (Apple Git-48)

Reply via email to