vga_switcheroo: split switching into two stages.
authorDave Airlie <airlied@redhat.com>
Tue, 7 Dec 2010 04:24:25 +0000 (14:24 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 5 Jan 2011 03:45:46 +0000 (13:45 +1000)
stage 1: turn card on, switch boot vga pointer.
stage 2: switch fbs, switch mux and power off old card.

Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/vga/vga_switcheroo.c

index 2b8e1d2..d2d8543 100644 (file)
@@ -212,7 +212,8 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
        return 0;
 }
 
-static int vga_switchto(struct vga_switcheroo_client *new_client)
+/* stage one happens before delay */
+static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
 {
        int ret;
        int i;
@@ -239,10 +240,28 @@ static int vga_switchto(struct vga_switcheroo_client *new_client)
                vga_switchon(new_client);
 
        /* swap shadow resource to denote boot VGA device has changed so X starts on new device */
-       active->active = false;
-
        active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW;
        new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+       return 0;
+}
+
+/* post delay */
+static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
+{
+       int ret;
+       int i;
+       struct vga_switcheroo_client *active = NULL;
+
+       for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
+               if (vgasr_priv.clients[i].active == true) {
+                       active = &vgasr_priv.clients[i];
+                       break;
+               }
+       }
+       if (!active)
+               return 0;
+
+       active->active = false;
 
        if (new_client->fb_info) {
                struct fb_event event;
@@ -368,18 +387,22 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
 
        if (can_switch == true) {
                pdev_name = pci_name(client->pdev);
-               ret = vga_switchto(client);
+               ret = vga_switchto_stage1(client);
+               if (ret)
+                       printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret);
+
+               ret = vga_switchto_stage2(client);
                if (ret)
-                       printk(KERN_ERR "vga_switcheroo: switching failed %d\n", ret);
+                       printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret);
+
        } else {
                printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id);
                vgasr_priv.delayed_switch_active = true;
                vgasr_priv.delayed_client_id = client_id;
 
-               /* we should at least power up the card to
-                  make the switch faster */
-               if (client->pwr_state == VGA_SWITCHEROO_OFF)
-                       vga_switchon(client);
+               ret = vga_switchto_stage1(client);
+               if (ret)
+                       printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret);
        }
 
 out:
@@ -461,9 +484,9 @@ int vga_switcheroo_process_delayed_switch(void)
                goto err;
 
        pdev_name = pci_name(client->pdev);
-       ret = vga_switchto(client);
+       ret = vga_switchto_stage2(client);
        if (ret)
-               printk(KERN_ERR "vga_switcheroo: delayed switching failed %d\n", ret);
+               printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret);
 
        vgasr_priv.delayed_switch_active = false;
        err = 0;