Skip to content

Commit

Permalink
i915: add suspend/resume support
Browse files Browse the repository at this point in the history
Add suspend/resume support to the i915 driver.  Moves some of the
initialization into the driver load routine, and fixes up places where we
assumed no dev_private existed in some of the cleanup paths.  This allows
us to suspend/resume properly even if X isn't running.

Signed-off-by: Dave Airlie <airlied@linux.ie>
  • Loading branch information
Jesse Barnes authored and Dave Airlie committed Feb 7, 2008
1 parent e8b962b commit ba8bbcf
Show file tree
Hide file tree
Showing 4 changed files with 1,309 additions and 57 deletions.
1 change: 1 addition & 0 deletions drivers/char/drm/drm_bufs.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)

return ret;
}
EXPORT_SYMBOL(drm_rmmap);

/* The rmmap ioctl appears to be unnecessary. All mappings are torn down on
* the last close of the device, and this is necessary for cleanup when things
Expand Down
113 changes: 57 additions & 56 deletions drivers/char/drm/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,6 @@
#include "i915_drm.h"
#include "i915_drv.h"

#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
dev->pci_device == 0x2982 || \
dev->pci_device == 0x2992 || \
dev->pci_device == 0x29A2 || \
dev->pci_device == 0x2A02 || \
dev->pci_device == 0x2A12)

#define IS_G33(dev) (dev->pci_device == 0x29b2 || \
dev->pci_device == 0x29c2 || \
dev->pci_device == 0x29d2)

/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
* the head pointer changes, so that EBUSY only happens if the ring
Expand Down Expand Up @@ -90,59 +79,50 @@ void i915_kernel_lost_context(struct drm_device * dev)

static int i915_dma_cleanup(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
if (dev->irq)
drm_irq_uninstall(dev);

if (dev->dev_private) {
drm_i915_private_t *dev_priv =
(drm_i915_private_t *) dev->dev_private;

if (dev_priv->ring.virtual_start) {
drm_core_ioremapfree(&dev_priv->ring.map, dev);
}

if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
/* Need to rewrite hardware status page */
I915_WRITE(0x02080, 0x1ffff000);
}

if (dev_priv->status_gfx_addr) {
dev_priv->status_gfx_addr = 0;
drm_core_ioremapfree(&dev_priv->hws_map, dev);
I915_WRITE(0x2080, 0x1ffff000);
}
if (dev_priv->ring.virtual_start) {
drm_core_ioremapfree(&dev_priv->ring.map, dev);
dev_priv->ring.virtual_start = 0;
dev_priv->ring.map.handle = 0;
dev_priv->ring.map.size = 0;
}

drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
dev_priv->status_page_dmah = NULL;
/* Need to rewrite hardware status page */
I915_WRITE(0x02080, 0x1ffff000);
}

dev->dev_private = NULL;
if (dev_priv->status_gfx_addr) {
dev_priv->status_gfx_addr = 0;
drm_core_ioremapfree(&dev_priv->hws_map, dev);
I915_WRITE(0x2080, 0x1ffff000);
}

return 0;
}

static int i915_initialize(struct drm_device * dev,
drm_i915_private_t * dev_priv,
drm_i915_init_t * init)
static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{
memset(dev_priv, 0, sizeof(drm_i915_private_t));
drm_i915_private_t *dev_priv = dev->dev_private;

dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
return -EINVAL;
}

dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
if (!dev_priv->mmio_map) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not find mmio map!\n");
return -EINVAL;
Expand All @@ -165,7 +145,6 @@ static int i915_initialize(struct drm_device * dev,
drm_core_ioremap(&dev_priv->ring.map, dev);

if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
Expand Down Expand Up @@ -197,7 +176,6 @@ static int i915_initialize(struct drm_device * dev,
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);

if (!dev_priv->status_page_dmah) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("Can not allocate hardware status page\n");
return -ENOMEM;
Expand All @@ -209,7 +187,6 @@ static int i915_initialize(struct drm_device * dev,
I915_WRITE(0x02080, dev_priv->dma_status_page);
}
DRM_DEBUG("Enabled hardware status page\n");
dev->dev_private = (void *)dev_priv;
return 0;
}

Expand Down Expand Up @@ -254,17 +231,12 @@ static int i915_dma_resume(struct drm_device * dev)
static int i915_dma_init(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv;
drm_i915_init_t *init = data;
int retcode = 0;

switch (init->func) {
case I915_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return -ENOMEM;
retcode = i915_initialize(dev, dev_priv, init);
retcode = i915_initialize(dev, init);
break;
case I915_CLEANUP_DMA:
retcode = i915_dma_cleanup(dev);
Expand Down Expand Up @@ -765,7 +737,6 @@ static int i915_set_status_page(struct drm_device *dev, void *data,

drm_core_ioremap(&dev_priv->hws_map, dev);
if (dev_priv->hws_map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
dev_priv->status_gfx_addr = 0;
DRM_ERROR("can not ioremap virtual address for"
Expand All @@ -784,31 +755,61 @@ static int i915_set_status_page(struct drm_device *dev, void *data,

int i915_driver_load(struct drm_device *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long base, size;
int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;

/* i915 has 4 more counters */
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
dev->types[7] = _DRM_STAT_PRIMARY;
dev->types[8] = _DRM_STAT_SECONDARY;
dev->types[9] = _DRM_STAT_DMA;

dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
return -ENOMEM;

memset(dev_priv, 0, sizeof(drm_i915_private_t));

dev->dev_private = (void *)dev_priv;

/* Add register map (needed for suspend/resume) */
base = drm_get_resource_start(dev, mmio_bar);
size = drm_get_resource_len(dev, mmio_bar);

ret = drm_addmap(dev, base, size, _DRM_REGISTERS, _DRM_KERNEL,
&dev_priv->mmio_map);
return ret;
}

int i915_driver_unload(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;

if (dev_priv->mmio_map)
drm_rmmap(dev, dev_priv->mmio_map);

drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);

return 0;
}

void i915_driver_lastclose(struct drm_device * dev)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_private_t *dev_priv = dev->dev_private;

if (dev_priv->agp_heap)
i915_mem_takedown(&(dev_priv->agp_heap));
}

i915_dma_cleanup(dev);
}

void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}

struct drm_ioctl_desc i915_ioctls[] = {
Expand Down
Loading

0 comments on commit ba8bbcf

Please sign in to comment.