@@ -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;
@@ -1380,16 +1378,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;
@@ -1398,10 +1388,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);
@@ -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)
{
@@ -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);