diff options
author | Jesse Barnes <jesse.barnes@intel.com> | 2007-11-21 23:14:14 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2008-02-07 00:09:38 -0500 |
commit | ba8bbcf6ff4650712f64c0ef61139c73898e2165 (patch) | |
tree | bd82043d355bdb060ec8291992bca912880f780a /drivers/char/drm/i915_dma.c | |
parent | e8b962b6df50b74afed14af7f7a7d569b3ba70ac (diff) |
i915: add suspend/resume support
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>
Diffstat (limited to 'drivers/char/drm/i915_dma.c')
-rw-r--r-- | drivers/char/drm/i915_dma.c | 113 |
1 files changed, 57 insertions, 56 deletions
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 842db3233e9e..b8db9652e9dd 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c | |||
@@ -31,17 +31,6 @@ | |||
31 | #include "i915_drm.h" | 31 | #include "i915_drm.h" |
32 | #include "i915_drv.h" | 32 | #include "i915_drv.h" |
33 | 33 | ||
34 | #define IS_I965G(dev) (dev->pci_device == 0x2972 || \ | ||
35 | dev->pci_device == 0x2982 || \ | ||
36 | dev->pci_device == 0x2992 || \ | ||
37 | dev->pci_device == 0x29A2 || \ | ||
38 | dev->pci_device == 0x2A02 || \ | ||
39 | dev->pci_device == 0x2A12) | ||
40 | |||
41 | #define IS_G33(dev) (dev->pci_device == 0x29b2 || \ | ||
42 | dev->pci_device == 0x29c2 || \ | ||
43 | dev->pci_device == 0x29d2) | ||
44 | |||
45 | /* Really want an OS-independent resettable timer. Would like to have | 34 | /* Really want an OS-independent resettable timer. Would like to have |
46 | * this loop run for (eg) 3 sec, but have the timer reset every time | 35 | * this loop run for (eg) 3 sec, but have the timer reset every time |
47 | * the head pointer changes, so that EBUSY only happens if the ring | 36 | * the head pointer changes, so that EBUSY only happens if the ring |
@@ -90,6 +79,7 @@ void i915_kernel_lost_context(struct drm_device * dev) | |||
90 | 79 | ||
91 | static int i915_dma_cleanup(struct drm_device * dev) | 80 | static int i915_dma_cleanup(struct drm_device * dev) |
92 | { | 81 | { |
82 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
93 | /* Make sure interrupts are disabled here because the uninstall ioctl | 83 | /* Make sure interrupts are disabled here because the uninstall ioctl |
94 | * may not have been called from userspace and after dev_private | 84 | * may not have been called from userspace and after dev_private |
95 | * is freed, it's too late. | 85 | * is freed, it's too late. |
@@ -97,52 +87,42 @@ static int i915_dma_cleanup(struct drm_device * dev) | |||
97 | if (dev->irq) | 87 | if (dev->irq) |
98 | drm_irq_uninstall(dev); | 88 | drm_irq_uninstall(dev); |
99 | 89 | ||
100 | if (dev->dev_private) { | 90 | if (dev_priv->ring.virtual_start) { |
101 | drm_i915_private_t *dev_priv = | 91 | drm_core_ioremapfree(&dev_priv->ring.map, dev); |
102 | (drm_i915_private_t *) dev->dev_private; | 92 | dev_priv->ring.virtual_start = 0; |
103 | 93 | dev_priv->ring.map.handle = 0; | |
104 | if (dev_priv->ring.virtual_start) { | 94 | dev_priv->ring.map.size = 0; |
105 | drm_core_ioremapfree(&dev_priv->ring.map, dev); | 95 | } |
106 | } | ||
107 | |||
108 | if (dev_priv->status_page_dmah) { | ||
109 | drm_pci_free(dev, dev_priv->status_page_dmah); | ||
110 | /* Need to rewrite hardware status page */ | ||
111 | I915_WRITE(0x02080, 0x1ffff000); | ||
112 | } | ||
113 | |||
114 | if (dev_priv->status_gfx_addr) { | ||
115 | dev_priv->status_gfx_addr = 0; | ||
116 | drm_core_ioremapfree(&dev_priv->hws_map, dev); | ||
117 | I915_WRITE(0x2080, 0x1ffff000); | ||
118 | } | ||
119 | 96 | ||
120 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), | 97 | if (dev_priv->status_page_dmah) { |
121 | DRM_MEM_DRIVER); | 98 | drm_pci_free(dev, dev_priv->status_page_dmah); |
99 | dev_priv->status_page_dmah = NULL; | ||
100 | /* Need to rewrite hardware status page */ | ||
101 | I915_WRITE(0x02080, 0x1ffff000); | ||
102 | } | ||
122 | 103 | ||
123 | dev->dev_private = NULL; | 104 | if (dev_priv->status_gfx_addr) { |
105 | dev_priv->status_gfx_addr = 0; | ||
106 | drm_core_ioremapfree(&dev_priv->hws_map, dev); | ||
107 | I915_WRITE(0x2080, 0x1ffff000); | ||
124 | } | 108 | } |
125 | 109 | ||
126 | return 0; | 110 | return 0; |
127 | } | 111 | } |
128 | 112 | ||
129 | static int i915_initialize(struct drm_device * dev, | 113 | static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) |
130 | drm_i915_private_t * dev_priv, | ||
131 | drm_i915_init_t * init) | ||
132 | { | 114 | { |
133 | memset(dev_priv, 0, sizeof(drm_i915_private_t)); | 115 | drm_i915_private_t *dev_priv = dev->dev_private; |
134 | 116 | ||
135 | dev_priv->sarea = drm_getsarea(dev); | 117 | dev_priv->sarea = drm_getsarea(dev); |
136 | if (!dev_priv->sarea) { | 118 | if (!dev_priv->sarea) { |
137 | DRM_ERROR("can not find sarea!\n"); | 119 | DRM_ERROR("can not find sarea!\n"); |
138 | dev->dev_private = (void *)dev_priv; | ||
139 | i915_dma_cleanup(dev); | 120 | i915_dma_cleanup(dev); |
140 | return -EINVAL; | 121 | return -EINVAL; |
141 | } | 122 | } |
142 | 123 | ||
143 | dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); | 124 | dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); |
144 | if (!dev_priv->mmio_map) { | 125 | if (!dev_priv->mmio_map) { |
145 | dev->dev_private = (void *)dev_priv; | ||
146 | i915_dma_cleanup(dev); | 126 | i915_dma_cleanup(dev); |
147 | DRM_ERROR("can not find mmio map!\n"); | 127 | DRM_ERROR("can not find mmio map!\n"); |
148 | return -EINVAL; | 128 | return -EINVAL; |
@@ -165,7 +145,6 @@ static int i915_initialize(struct drm_device * dev, | |||
165 | drm_core_ioremap(&dev_priv->ring.map, dev); | 145 | drm_core_ioremap(&dev_priv->ring.map, dev); |
166 | 146 | ||
167 | if (dev_priv->ring.map.handle == NULL) { | 147 | if (dev_priv->ring.map.handle == NULL) { |
168 | dev->dev_private = (void *)dev_priv; | ||
169 | i915_dma_cleanup(dev); | 148 | i915_dma_cleanup(dev); |
170 | DRM_ERROR("can not ioremap virtual address for" | 149 | DRM_ERROR("can not ioremap virtual address for" |
171 | " ring buffer\n"); | 150 | " ring buffer\n"); |
@@ -197,7 +176,6 @@ static int i915_initialize(struct drm_device * dev, | |||
197 | drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); | 176 | drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); |
198 | 177 | ||
199 | if (!dev_priv->status_page_dmah) { | 178 | if (!dev_priv->status_page_dmah) { |
200 | dev->dev_private = (void *)dev_priv; | ||
201 | i915_dma_cleanup(dev); | 179 | i915_dma_cleanup(dev); |
202 | DRM_ERROR("Can not allocate hardware status page\n"); | 180 | DRM_ERROR("Can not allocate hardware status page\n"); |
203 | return -ENOMEM; | 181 | return -ENOMEM; |
@@ -209,7 +187,6 @@ static int i915_initialize(struct drm_device * dev, | |||
209 | I915_WRITE(0x02080, dev_priv->dma_status_page); | 187 | I915_WRITE(0x02080, dev_priv->dma_status_page); |
210 | } | 188 | } |
211 | DRM_DEBUG("Enabled hardware status page\n"); | 189 | DRM_DEBUG("Enabled hardware status page\n"); |
212 | dev->dev_private = (void *)dev_priv; | ||
213 | return 0; | 190 | return 0; |
214 | } | 191 | } |
215 | 192 | ||
@@ -254,17 +231,12 @@ static int i915_dma_resume(struct drm_device * dev) | |||
254 | static int i915_dma_init(struct drm_device *dev, void *data, | 231 | static int i915_dma_init(struct drm_device *dev, void *data, |
255 | struct drm_file *file_priv) | 232 | struct drm_file *file_priv) |
256 | { | 233 | { |
257 | drm_i915_private_t *dev_priv; | ||
258 | drm_i915_init_t *init = data; | 234 | drm_i915_init_t *init = data; |
259 | int retcode = 0; | 235 | int retcode = 0; |
260 | 236 | ||
261 | switch (init->func) { | 237 | switch (init->func) { |
262 | case I915_INIT_DMA: | 238 | case I915_INIT_DMA: |
263 | dev_priv = drm_alloc(sizeof(drm_i915_private_t), | 239 | retcode = i915_initialize(dev, init); |
264 | DRM_MEM_DRIVER); | ||
265 | if (dev_priv == NULL) | ||
266 | return -ENOMEM; | ||
267 | retcode = i915_initialize(dev, dev_priv, init); | ||
268 | break; | 240 | break; |
269 | case I915_CLEANUP_DMA: | 241 | case I915_CLEANUP_DMA: |
270 | retcode = i915_dma_cleanup(dev); | 242 | retcode = i915_dma_cleanup(dev); |
@@ -765,7 +737,6 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
765 | 737 | ||
766 | drm_core_ioremap(&dev_priv->hws_map, dev); | 738 | drm_core_ioremap(&dev_priv->hws_map, dev); |
767 | if (dev_priv->hws_map.handle == NULL) { | 739 | if (dev_priv->hws_map.handle == NULL) { |
768 | dev->dev_private = (void *)dev_priv; | ||
769 | i915_dma_cleanup(dev); | 740 | i915_dma_cleanup(dev); |
770 | dev_priv->status_gfx_addr = 0; | 741 | dev_priv->status_gfx_addr = 0; |
771 | DRM_ERROR("can not ioremap virtual address for" | 742 | DRM_ERROR("can not ioremap virtual address for" |
@@ -784,6 +755,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
784 | 755 | ||
785 | int i915_driver_load(struct drm_device *dev, unsigned long flags) | 756 | int i915_driver_load(struct drm_device *dev, unsigned long flags) |
786 | { | 757 | { |
758 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
759 | unsigned long base, size; | ||
760 | int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; | ||
761 | |||
787 | /* i915 has 4 more counters */ | 762 | /* i915 has 4 more counters */ |
788 | dev->counters += 4; | 763 | dev->counters += 4; |
789 | dev->types[6] = _DRM_STAT_IRQ; | 764 | dev->types[6] = _DRM_STAT_IRQ; |
@@ -791,24 +766,50 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
791 | dev->types[8] = _DRM_STAT_SECONDARY; | 766 | dev->types[8] = _DRM_STAT_SECONDARY; |
792 | dev->types[9] = _DRM_STAT_DMA; | 767 | dev->types[9] = _DRM_STAT_DMA; |
793 | 768 | ||
769 | dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); | ||
770 | if (dev_priv == NULL) | ||
771 | return -ENOMEM; | ||
772 | |||
773 | memset(dev_priv, 0, sizeof(drm_i915_private_t)); | ||
774 | |||
775 | dev->dev_private = (void *)dev_priv; | ||
776 | |||
777 | /* Add register map (needed for suspend/resume) */ | ||
778 | base = drm_get_resource_start(dev, mmio_bar); | ||
779 | size = drm_get_resource_len(dev, mmio_bar); | ||
780 | |||
781 | ret = drm_addmap(dev, base, size, _DRM_REGISTERS, _DRM_KERNEL, | ||
782 | &dev_priv->mmio_map); | ||
783 | return ret; | ||
784 | } | ||
785 | |||
786 | int i915_driver_unload(struct drm_device *dev) | ||
787 | { | ||
788 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
789 | |||
790 | if (dev_priv->mmio_map) | ||
791 | drm_rmmap(dev, dev_priv->mmio_map); | ||
792 | |||
793 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), | ||
794 | DRM_MEM_DRIVER); | ||
795 | |||
794 | return 0; | 796 | return 0; |
795 | } | 797 | } |
796 | 798 | ||
797 | void i915_driver_lastclose(struct drm_device * dev) | 799 | void i915_driver_lastclose(struct drm_device * dev) |
798 | { | 800 | { |
799 | if (dev->dev_private) { | 801 | drm_i915_private_t *dev_priv = dev->dev_private; |
800 | drm_i915_private_t *dev_priv = dev->dev_private; | 802 | |
803 | if (dev_priv->agp_heap) | ||
801 | i915_mem_takedown(&(dev_priv->agp_heap)); | 804 | i915_mem_takedown(&(dev_priv->agp_heap)); |
802 | } | 805 | |
803 | i915_dma_cleanup(dev); | 806 | i915_dma_cleanup(dev); |
804 | } | 807 | } |
805 | 808 | ||
806 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) | 809 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) |
807 | { | 810 | { |
808 | if (dev->dev_private) { | 811 | drm_i915_private_t *dev_priv = dev->dev_private; |
809 | drm_i915_private_t *dev_priv = dev->dev_private; | 812 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); |
810 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | ||
811 | } | ||
812 | } | 813 | } |
813 | 814 | ||
814 | struct drm_ioctl_desc i915_ioctls[] = { | 815 | struct drm_ioctl_desc i915_ioctls[] = { |