vmwgfx: vt-switch (master drop) fixes

We add an option not to enable fbdev, this option is off (0) by default.
Not enabling fbdev at load time makes it possible to co-operate with
vga16fb and vga text mode when VT switching.

However, if 3D resources are active when VT switching, we're currently
not able to switch over to vga, due to device limitations.
This fixes a bug where we previously lost 3D state during VT switch.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Thomas Hellstrom 2010-10-01 10:21:48 +02:00 committed by Dave Airlie
parent 2854eedae2
commit 30c78bb838
5 changed files with 115 additions and 13 deletions

View File

@ -149,12 +149,16 @@ static struct pci_device_id vmw_pci_id_list[] = {
}; };
static char *vmw_devname = "vmwgfx"; static char *vmw_devname = "vmwgfx";
static int enable_fbdev;
static int vmw_probe(struct pci_dev *, const struct pci_device_id *); static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
static void vmw_master_init(struct vmw_master *); static void vmw_master_init(struct vmw_master *);
static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
void *ptr); void *ptr);
MODULE_PARM_DESC(enable_fbdev, "Enable vmwgfx fbdev");
module_param_named(enable_fbdev, enable_fbdev, int, 0600);
static void vmw_print_capabilities(uint32_t capabilities) static void vmw_print_capabilities(uint32_t capabilities)
{ {
DRM_INFO("Capabilities:\n"); DRM_INFO("Capabilities:\n");
@ -192,8 +196,6 @@ static int vmw_request_device(struct vmw_private *dev_priv)
{ {
int ret; int ret;
vmw_kms_save_vga(dev_priv);
ret = vmw_fifo_init(dev_priv, &dev_priv->fifo); ret = vmw_fifo_init(dev_priv, &dev_priv->fifo);
if (unlikely(ret != 0)) { if (unlikely(ret != 0)) {
DRM_ERROR("Unable to initialize FIFO.\n"); DRM_ERROR("Unable to initialize FIFO.\n");
@ -206,9 +208,35 @@ static int vmw_request_device(struct vmw_private *dev_priv)
static void vmw_release_device(struct vmw_private *dev_priv) static void vmw_release_device(struct vmw_private *dev_priv)
{ {
vmw_fifo_release(dev_priv, &dev_priv->fifo); vmw_fifo_release(dev_priv, &dev_priv->fifo);
vmw_kms_restore_vga(dev_priv);
} }
int vmw_3d_resource_inc(struct vmw_private *dev_priv)
{
int ret = 0;
mutex_lock(&dev_priv->release_mutex);
if (unlikely(dev_priv->num_3d_resources++ == 0)) {
ret = vmw_request_device(dev_priv);
if (unlikely(ret != 0))
--dev_priv->num_3d_resources;
}
mutex_unlock(&dev_priv->release_mutex);
return ret;
}
void vmw_3d_resource_dec(struct vmw_private *dev_priv)
{
int32_t n3d;
mutex_lock(&dev_priv->release_mutex);
if (unlikely(--dev_priv->num_3d_resources == 0))
vmw_release_device(dev_priv);
n3d = (int32_t) dev_priv->num_3d_resources;
mutex_unlock(&dev_priv->release_mutex);
BUG_ON(n3d < 0);
}
static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
{ {
@ -228,6 +256,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->last_read_sequence = (uint32_t) -100; dev_priv->last_read_sequence = (uint32_t) -100;
mutex_init(&dev_priv->hw_mutex); mutex_init(&dev_priv->hw_mutex);
mutex_init(&dev_priv->cmdbuf_mutex); mutex_init(&dev_priv->cmdbuf_mutex);
mutex_init(&dev_priv->release_mutex);
rwlock_init(&dev_priv->resource_lock); rwlock_init(&dev_priv->resource_lock);
idr_init(&dev_priv->context_idr); idr_init(&dev_priv->context_idr);
idr_init(&dev_priv->surface_idr); idr_init(&dev_priv->surface_idr);
@ -244,6 +273,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->vram_start = pci_resource_start(dev->pdev, 1); dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
dev_priv->enable_fb = enable_fbdev;
mutex_lock(&dev_priv->hw_mutex); mutex_lock(&dev_priv->hw_mutex);
vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
@ -369,20 +400,34 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
goto out_no_device; goto out_no_device;
} }
} }
ret = vmw_request_device(dev_priv);
if (unlikely(ret != 0))
goto out_no_device;
vmw_kms_init(dev_priv); vmw_kms_init(dev_priv);
vmw_overlay_init(dev_priv); vmw_overlay_init(dev_priv);
vmw_fb_init(dev_priv); if (dev_priv->enable_fb) {
ret = vmw_3d_resource_inc(dev_priv);
if (unlikely(ret != 0))
goto out_no_fifo;
vmw_kms_save_vga(dev_priv);
vmw_fb_init(dev_priv);
DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ?
"Detected device 3D availability.\n" :
"Detected no device 3D availability.\n");
} else {
DRM_INFO("Delayed 3D detection since we're not "
"running the device in SVGA mode yet.\n");
}
dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
register_pm_notifier(&dev_priv->pm_nb); register_pm_notifier(&dev_priv->pm_nb);
DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n");
return 0; return 0;
out_no_fifo:
vmw_overlay_close(dev_priv);
vmw_kms_close(dev_priv);
if (dev_priv->stealth)
pci_release_region(dev->pdev, 2);
else
pci_release_regions(dev->pdev);
out_no_device: out_no_device:
if (dev_priv->capabilities & SVGA_CAP_IRQMASK) if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
drm_irq_uninstall(dev_priv->dev); drm_irq_uninstall(dev_priv->dev);
@ -415,10 +460,13 @@ static int vmw_driver_unload(struct drm_device *dev)
unregister_pm_notifier(&dev_priv->pm_nb); unregister_pm_notifier(&dev_priv->pm_nb);
vmw_fb_close(dev_priv); if (dev_priv->enable_fb) {
vmw_fb_close(dev_priv);
vmw_kms_restore_vga(dev_priv);
vmw_3d_resource_dec(dev_priv);
}
vmw_kms_close(dev_priv); vmw_kms_close(dev_priv);
vmw_overlay_close(dev_priv); vmw_overlay_close(dev_priv);
vmw_release_device(dev_priv);
if (dev_priv->stealth) if (dev_priv->stealth)
pci_release_region(dev->pdev, 2); pci_release_region(dev->pdev, 2);
else else
@ -589,6 +637,16 @@ static int vmw_master_set(struct drm_device *dev,
struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret = 0; int ret = 0;
if (!dev_priv->enable_fb) {
ret = vmw_3d_resource_inc(dev_priv);
if (unlikely(ret != 0))
return ret;
vmw_kms_save_vga(dev_priv);
mutex_lock(&dev_priv->hw_mutex);
vmw_write(dev_priv, SVGA_REG_TRACES, 0);
mutex_unlock(&dev_priv->hw_mutex);
}
if (active) { if (active) {
BUG_ON(active != &dev_priv->fbdev_master); BUG_ON(active != &dev_priv->fbdev_master);
ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile); ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile);
@ -617,7 +675,13 @@ static int vmw_master_set(struct drm_device *dev,
return 0; return 0;
out_no_active_lock: out_no_active_lock:
vmw_release_device(dev_priv); if (!dev_priv->enable_fb) {
mutex_lock(&dev_priv->hw_mutex);
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);
}
return ret; return ret;
} }
@ -645,11 +709,23 @@ static void vmw_master_drop(struct drm_device *dev,
ttm_lock_set_kill(&vmaster->lock, true, SIGTERM); ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
if (!dev_priv->enable_fb) {
ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
if (unlikely(ret != 0))
DRM_ERROR("Unable to clean VRAM on master drop.\n");
mutex_lock(&dev_priv->hw_mutex);
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);
}
dev_priv->active_master = &dev_priv->fbdev_master; dev_priv->active_master = &dev_priv->fbdev_master;
ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
ttm_vt_unlock(&dev_priv->fbdev_master.lock); ttm_vt_unlock(&dev_priv->fbdev_master.lock);
vmw_fb_on(dev_priv); if (dev_priv->enable_fb)
vmw_fb_on(dev_priv);
} }

View File

@ -277,6 +277,7 @@ struct vmw_private {
bool stealth; bool stealth;
bool is_opened; bool is_opened;
bool enable_fb;
/** /**
* Master management. * Master management.
@ -285,6 +286,9 @@ struct vmw_private {
struct vmw_master *active_master; struct vmw_master *active_master;
struct vmw_master fbdev_master; struct vmw_master fbdev_master;
struct notifier_block pm_nb; struct notifier_block pm_nb;
struct mutex release_mutex;
uint32_t num_3d_resources;
}; };
static inline struct vmw_private *vmw_priv(struct drm_device *dev) static inline struct vmw_private *vmw_priv(struct drm_device *dev)
@ -319,6 +323,9 @@ static inline uint32_t vmw_read(struct vmw_private *dev_priv,
return val; return val;
} }
int vmw_3d_resource_inc(struct vmw_private *dev_priv);
void vmw_3d_resource_dec(struct vmw_private *dev_priv);
/** /**
* GMR utilities - vmwgfx_gmr.c * GMR utilities - vmwgfx_gmr.c
*/ */

View File

@ -106,6 +106,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
mutex_lock(&dev_priv->hw_mutex); mutex_lock(&dev_priv->hw_mutex);
dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE);
dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE);
dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES);
vmw_write(dev_priv, SVGA_REG_ENABLE, 1); vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
min = 4; min = 4;
@ -175,6 +176,8 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
dev_priv->config_done_state); dev_priv->config_done_state);
vmw_write(dev_priv, SVGA_REG_ENABLE, vmw_write(dev_priv, SVGA_REG_ENABLE,
dev_priv->enable_state); dev_priv->enable_state);
vmw_write(dev_priv, SVGA_REG_TRACES,
dev_priv->traces_state);
mutex_unlock(&dev_priv->hw_mutex); mutex_unlock(&dev_priv->hw_mutex);
vmw_fence_queue_takedown(&fifo->fence_queue); vmw_fence_queue_takedown(&fifo->fence_queue);

View File

@ -898,7 +898,19 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH); save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH);
save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT); save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
if (i == 0 && vmw_priv->num_displays == 1 &&
save->width == 0 && save->height == 0) {
/*
* It should be fairly safe to assume that these
* values are uninitialized.
*/
save->width = vmw_priv->vga_width - save->pos_x;
save->height = vmw_priv->vga_height - save->pos_y;
}
} }
return 0; return 0;
} }

View File

@ -211,6 +211,7 @@ static void vmw_hw_context_destroy(struct vmw_resource *res)
cmd->body.cid = cpu_to_le32(res->id); cmd->body.cid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd)); vmw_fifo_commit(dev_priv, sizeof(*cmd));
vmw_3d_resource_dec(dev_priv);
} }
static int vmw_context_init(struct vmw_private *dev_priv, static int vmw_context_init(struct vmw_private *dev_priv,
@ -247,6 +248,7 @@ static int vmw_context_init(struct vmw_private *dev_priv,
cmd->body.cid = cpu_to_le32(res->id); cmd->body.cid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd)); vmw_fifo_commit(dev_priv, sizeof(*cmd));
(void) vmw_3d_resource_inc(dev_priv);
vmw_resource_activate(res, vmw_hw_context_destroy); vmw_resource_activate(res, vmw_hw_context_destroy);
return 0; return 0;
} }
@ -406,6 +408,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res)
cmd->body.sid = cpu_to_le32(res->id); cmd->body.sid = cpu_to_le32(res->id);
vmw_fifo_commit(dev_priv, sizeof(*cmd)); vmw_fifo_commit(dev_priv, sizeof(*cmd));
vmw_3d_resource_dec(dev_priv);
} }
void vmw_surface_res_free(struct vmw_resource *res) void vmw_surface_res_free(struct vmw_resource *res)
@ -473,6 +476,7 @@ int vmw_surface_init(struct vmw_private *dev_priv,
} }
vmw_fifo_commit(dev_priv, submit_size); vmw_fifo_commit(dev_priv, submit_size);
(void) vmw_3d_resource_inc(dev_priv);
vmw_resource_activate(res, vmw_hw_surface_destroy); vmw_resource_activate(res, vmw_hw_surface_destroy);
return 0; return 0;
} }