]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
vmwgfx: Switch to VGA when we drop master and vmwgfx fbdev is not active
[karo-tx-linux.git] / drivers / gpu / drm / vmwgfx / vmwgfx_drv.c
index 62d54b940474f7b20585dc493d1bad0707b6816c..3d6a073e130b2aa1855d2cc25a1ca456fea82d6a 100644 (file)
@@ -209,7 +209,14 @@ static void vmw_release_device(struct vmw_private *dev_priv)
        vmw_fifo_release(dev_priv, &dev_priv->fifo);
 }
 
-int vmw_3d_resource_inc(struct vmw_private *dev_priv)
+/**
+ * Increase the 3d resource refcount.
+ * If the count was prevously zero, initialize the fifo, switching to svga
+ * mode. Note that the master holds a ref as well, and may request an
+ * explicit switch to svga mode if fb is not running, using @unhide_svga.
+ */
+int vmw_3d_resource_inc(struct vmw_private *dev_priv,
+                       bool unhide_svga)
 {
        int ret = 0;
 
@@ -218,19 +225,42 @@ int vmw_3d_resource_inc(struct vmw_private *dev_priv)
                ret = vmw_request_device(dev_priv);
                if (unlikely(ret != 0))
                        --dev_priv->num_3d_resources;
+       } else if (unhide_svga) {
+               mutex_lock(&dev_priv->hw_mutex);
+               vmw_write(dev_priv, SVGA_REG_ENABLE,
+                         vmw_read(dev_priv, SVGA_REG_ENABLE) &
+                         ~SVGA_REG_ENABLE_HIDE);
+               mutex_unlock(&dev_priv->hw_mutex);
        }
+
        mutex_unlock(&dev_priv->release_mutex);
        return ret;
 }
 
-
-void vmw_3d_resource_dec(struct vmw_private *dev_priv)
+/**
+ * Decrease the 3d resource refcount.
+ * If the count reaches zero, disable the fifo, switching to vga mode.
+ * Note that the master holds a refcount as well, and may request an
+ * explicit switch to vga mode when it releases its refcount to account
+ * for the situation of an X server vt switch to VGA with 3d resources
+ * active.
+ */
+void vmw_3d_resource_dec(struct vmw_private *dev_priv,
+                        bool hide_svga)
 {
        int32_t n3d;
 
        mutex_lock(&dev_priv->release_mutex);
        if (unlikely(--dev_priv->num_3d_resources == 0))
                vmw_release_device(dev_priv);
+       else if (hide_svga) {
+               mutex_lock(&dev_priv->hw_mutex);
+               vmw_write(dev_priv, SVGA_REG_ENABLE,
+                         vmw_read(dev_priv, SVGA_REG_ENABLE) |
+                         SVGA_REG_ENABLE_HIDE);
+               mutex_unlock(&dev_priv->hw_mutex);
+       }
+
        n3d = (int32_t) dev_priv->num_3d_resources;
        mutex_unlock(&dev_priv->release_mutex);
 
@@ -399,7 +429,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                goto out_no_kms;
        vmw_overlay_init(dev_priv);
        if (dev_priv->enable_fb) {
-               ret = vmw_3d_resource_inc(dev_priv);
+               ret = vmw_3d_resource_inc(dev_priv, false);
                if (unlikely(ret != 0))
                        goto out_no_fifo;
                vmw_kms_save_vga(dev_priv);
@@ -429,7 +459,7 @@ out_no_irq:
        if (dev_priv->enable_fb) {
                vmw_fb_close(dev_priv);
                vmw_kms_restore_vga(dev_priv);
-               vmw_3d_resource_dec(dev_priv);
+               vmw_3d_resource_dec(dev_priv, false);
        }
 out_no_fifo:
        vmw_overlay_close(dev_priv);
@@ -474,7 +504,7 @@ static int vmw_driver_unload(struct drm_device *dev)
        if (dev_priv->enable_fb) {
                vmw_fb_close(dev_priv);
                vmw_kms_restore_vga(dev_priv);
-               vmw_3d_resource_dec(dev_priv);
+               vmw_3d_resource_dec(dev_priv, false);
        }
        vmw_kms_close(dev_priv);
        vmw_overlay_close(dev_priv);
@@ -648,7 +678,7 @@ static int vmw_master_set(struct drm_device *dev,
        int ret = 0;
 
        if (!dev_priv->enable_fb) {
-               ret = vmw_3d_resource_inc(dev_priv);
+               ret = vmw_3d_resource_inc(dev_priv, true);
                if (unlikely(ret != 0))
                        return ret;
                vmw_kms_save_vga(dev_priv);
@@ -690,7 +720,7 @@ out_no_active_lock:
                vmw_write(dev_priv, SVGA_REG_TRACES, 1);
                mutex_unlock(&dev_priv->hw_mutex);
                vmw_kms_restore_vga(dev_priv);
-               vmw_3d_resource_dec(dev_priv);
+               vmw_3d_resource_dec(dev_priv, true);
        }
        return ret;
 }
@@ -728,7 +758,7 @@ static void vmw_master_drop(struct drm_device *dev,
                vmw_write(dev_priv, SVGA_REG_TRACES, 1);
                mutex_unlock(&dev_priv->hw_mutex);
                vmw_kms_restore_vga(dev_priv);
-               vmw_3d_resource_dec(dev_priv);
+               vmw_3d_resource_dec(dev_priv, true);
        }
 
        dev_priv->active_master = &dev_priv->fbdev_master;
@@ -837,7 +867,7 @@ static int vmw_pm_prepare(struct device *kdev)
         */
        dev_priv->suspended = true;
        if (dev_priv->enable_fb)
-               vmw_3d_resource_dec(dev_priv);
+                       vmw_3d_resource_dec(dev_priv, true);
 
        if (dev_priv->num_3d_resources != 0) {
 
@@ -845,7 +875,7 @@ static int vmw_pm_prepare(struct device *kdev)
                         "while 3D resources are active.\n");
 
                if (dev_priv->enable_fb)
-                       vmw_3d_resource_inc(dev_priv);
+                       vmw_3d_resource_inc(dev_priv, true);
                dev_priv->suspended = false;
                return -EBUSY;
        }
@@ -864,7 +894,7 @@ static void vmw_pm_complete(struct device *kdev)
         * start fifo.
         */
        if (dev_priv->enable_fb)
-               vmw_3d_resource_inc(dev_priv);
+                       vmw_3d_resource_inc(dev_priv, false);
 
        dev_priv->suspended = false;
 }