[PATCH v2 11/22] vga_switcheroo: Generate hotplug event on handler and proxy registration

Lukas Wunner lukas at wunner.de
Wed Aug 12 04:39:54 PDT 2015


On laptops which require the handler to switch DDC lines, already
registered clients must reprobe their connectors if the handler
registers late. This is the case on pre-retina MacBook Pros,
which use a gmux controller as handler.

Based (loosely) on a patch by Matthew Garrett <mjg59 at srcf.ucam.org>
who used an additional driver callback rather than generating a
hotplug event:
http://lists.freedesktop.org/archives/dri-devel/2014-June/060941.html

Matthew Garrett invoked the driver callback in vga_switcheroo_enable().
On pre-retina MacBook Pros, this delayed reprobing until a second gpu
registers, which may never happen if its driver is not installed or
blacklisted. The MacBook Pro 2011 in particular suffers from widespread
gpu soldering issues due to overheating, eventually rendering it
unusable with OS X. Folks are solving this by moving to Linux and
disabling the discrete gpu entirely. In those cases we can't wait
for a second gpu to register, we do need to reprobe as soon as the
handler registers:
https://ifixit.org/blog/6882/why-i-drilled-holes-in-my-macbook-pro-and-put-it-in-the-oven/#comment-26745

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Paul Hordiienko <pvt.gord at gmail.com>
    [MBP  6,2 2010  intel ILK + nvidia GT216  pre-retina]
Tested-by: William Brown <william at blackhats.net.au>
    [MBP  8,2 2011  intel SNB + amd turks     pre-retina]
Tested-by: Lukas Wunner <lukas at wunner.de>
    [MBP  9,1 2012  intel IVB + nvidia GK107  pre-retina]
Tested-by: Bruno Bierbaumer <bruno at bierbaumer.net>
    [MBP 11,3 2013  intel HSW + nvidia GK107  retina -- work in progress]

Signed-off-by: Lukas Wunner <lukas at wunner.de>
---
 drivers/gpu/vga/vga_switcheroo.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 8027c9f..94b0b6f 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -18,6 +18,8 @@
  - can_switch - check if the device is in a position to switch now
  */
 
+#include <drm/drm_crtc_helper.h>
+
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
@@ -35,6 +37,7 @@
 struct vga_switcheroo_client {
 	struct pci_dev *pdev;
 	struct fb_info *fb_info;
+	struct work_struct reprobe_work;
 	int pwr_state;
 	const struct vga_switcheroo_client_ops *ops;
 	int id;
@@ -106,6 +109,30 @@ static void vga_switcheroo_enable(void)
 	vgasr_priv.active = true;
 }
 
+static void vga_switcheroo_reprobe_client(struct work_struct *work)
+{
+	struct vga_switcheroo_client *client =
+		container_of(work, struct vga_switcheroo_client, reprobe_work);
+	void (*generate_hotplug_event)(struct drm_device *);
+
+	generate_hotplug_event = symbol_get(drm_kms_helper_hotplug_event);
+	if (!generate_hotplug_event)
+		return;
+
+	generate_hotplug_event(pci_get_drvdata(client->pdev));
+}
+
+static void vga_switcheroo_reprobe_inactive_clients(void)
+{
+	struct vga_switcheroo_client *client;
+
+	list_for_each_entry(client, &vgasr_priv.clients, list)
+		if (!client->active && client_is_vga(client)) {
+			cancel_work_sync(&client->reprobe_work);
+			schedule_work(&client->reprobe_work);
+		}
+}
+
 int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
 {
 	mutex_lock(&vgasr_mutex);
@@ -115,11 +142,17 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
 	}
 
 	vgasr_priv.handler = handler;
+
 	if (vga_switcheroo_ready()) {
 		printk(KERN_INFO "vga_switcheroo: enabled\n");
 		vga_switcheroo_enable();
 	}
 	mutex_unlock(&vgasr_mutex);
+
+	/* clients which registered before the handler must reprobe */
+	if (vgasr_priv.handler->switch_ddc)
+		vga_switcheroo_reprobe_inactive_clients();
+
 	return 0;
 }
 EXPORT_SYMBOL(vga_switcheroo_register_handler);
@@ -153,6 +186,7 @@ static int register_client(struct pci_dev *pdev,
 	client->id = id;
 	client->active = active;
 	client->driver_power_control = driver_power_control;
+	INIT_WORK(&client->reprobe_work, vga_switcheroo_reprobe_client);
 
 	mutex_lock(&vgasr_mutex);
 	list_add_tail(&client->list, &vgasr_priv.clients);
-- 
1.8.5.2 (Apple Git-48)



More information about the dri-devel mailing list