diff options
author | Keith Packard <keithp@keithp.com> | 2008-07-30 16:03:43 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2008-10-17 17:10:10 -0400 |
commit | 398c9cb20b5c6c5d1313912b937d653a46fec578 (patch) | |
tree | fab5398ec4bab85394cee9df4f4e34a002480bc9 /drivers/gpu | |
parent | d3a6d4467ca44833bcb4ba1893a7aeaae939e4d5 (diff) |
i915: Initialize hardware status page at device load when possible.
Some chips were unstable with repeated setup/teardown of the hardware status
page.
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 86 |
1 files changed, 57 insertions, 29 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index aa9e8da9f716..f1b5aa92fa83 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -71,6 +71,52 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) | |||
71 | return -EBUSY; | 71 | return -EBUSY; |
72 | } | 72 | } |
73 | 73 | ||
74 | /** | ||
75 | * Sets up the hardware status page for devices that need a physical address | ||
76 | * in the register. | ||
77 | */ | ||
78 | int i915_init_phys_hws(struct drm_device *dev) | ||
79 | { | ||
80 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
81 | /* Program Hardware Status Page */ | ||
82 | dev_priv->status_page_dmah = | ||
83 | drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); | ||
84 | |||
85 | if (!dev_priv->status_page_dmah) { | ||
86 | DRM_ERROR("Can not allocate hardware status page\n"); | ||
87 | return -ENOMEM; | ||
88 | } | ||
89 | dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; | ||
90 | dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; | ||
91 | |||
92 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); | ||
93 | |||
94 | I915_WRITE(HWS_PGA, dev_priv->dma_status_page); | ||
95 | DRM_DEBUG("Enabled hardware status page\n"); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * Frees the hardware status page, whether it's a physical address or a virtual | ||
101 | * address set up by the X Server. | ||
102 | */ | ||
103 | void i915_free_hws(struct drm_device *dev) | ||
104 | { | ||
105 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
106 | if (dev_priv->status_page_dmah) { | ||
107 | drm_pci_free(dev, dev_priv->status_page_dmah); | ||
108 | dev_priv->status_page_dmah = NULL; | ||
109 | } | ||
110 | |||
111 | if (dev_priv->status_gfx_addr) { | ||
112 | dev_priv->status_gfx_addr = 0; | ||
113 | drm_core_ioremapfree(&dev_priv->hws_map, dev); | ||
114 | } | ||
115 | |||
116 | /* Need to rewrite hardware status page */ | ||
117 | I915_WRITE(HWS_PGA, 0x1ffff000); | ||
118 | } | ||
119 | |||
74 | void i915_kernel_lost_context(struct drm_device * dev) | 120 | void i915_kernel_lost_context(struct drm_device * dev) |
75 | { | 121 | { |
76 | drm_i915_private_t *dev_priv = dev->dev_private; | 122 | drm_i915_private_t *dev_priv = dev->dev_private; |
@@ -103,18 +149,9 @@ static int i915_dma_cleanup(struct drm_device * dev) | |||
103 | dev_priv->ring.map.size = 0; | 149 | dev_priv->ring.map.size = 0; |
104 | } | 150 | } |
105 | 151 | ||
106 | if (dev_priv->status_page_dmah) { | 152 | /* Clear the HWS virtual address at teardown */ |
107 | drm_pci_free(dev, dev_priv->status_page_dmah); | 153 | if (I915_NEED_GFX_HWS(dev)) |
108 | dev_priv->status_page_dmah = NULL; | 154 | i915_free_hws(dev); |
109 | /* Need to rewrite hardware status page */ | ||
110 | I915_WRITE(HWS_PGA, 0x1ffff000); | ||
111 | } | ||
112 | |||
113 | if (dev_priv->status_gfx_addr) { | ||
114 | dev_priv->status_gfx_addr = 0; | ||
115 | drm_core_ioremapfree(&dev_priv->hws_map, dev); | ||
116 | I915_WRITE(HWS_PGA, 0x1ffff000); | ||
117 | } | ||
118 | 155 | ||
119 | return 0; | 156 | return 0; |
120 | } | 157 | } |
@@ -165,23 +202,6 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) | |||
165 | */ | 202 | */ |
166 | dev_priv->allow_batchbuffer = 1; | 203 | dev_priv->allow_batchbuffer = 1; |
167 | 204 | ||
168 | /* Program Hardware Status Page */ | ||
169 | if (!I915_NEED_GFX_HWS(dev)) { | ||
170 | dev_priv->status_page_dmah = | ||
171 | drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); | ||
172 | |||
173 | if (!dev_priv->status_page_dmah) { | ||
174 | i915_dma_cleanup(dev); | ||
175 | DRM_ERROR("Can not allocate hardware status page\n"); | ||
176 | return -ENOMEM; | ||
177 | } | ||
178 | dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; | ||
179 | dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; | ||
180 | |||
181 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); | ||
182 | I915_WRITE(HWS_PGA, dev_priv->dma_status_page); | ||
183 | } | ||
184 | DRM_DEBUG("Enabled hardware status page\n"); | ||
185 | return 0; | 205 | return 0; |
186 | } | 206 | } |
187 | 207 | ||
@@ -773,6 +793,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
773 | _DRM_KERNEL | _DRM_DRIVER, | 793 | _DRM_KERNEL | _DRM_DRIVER, |
774 | &dev_priv->mmio_map); | 794 | &dev_priv->mmio_map); |
775 | 795 | ||
796 | /* Init HWS */ | ||
797 | if (!I915_NEED_GFX_HWS(dev)) { | ||
798 | ret = i915_init_phys_hws(dev); | ||
799 | if (ret != 0) | ||
800 | return ret; | ||
801 | } | ||
776 | 802 | ||
777 | /* On the 945G/GM, the chipset reports the MSI capability on the | 803 | /* On the 945G/GM, the chipset reports the MSI capability on the |
778 | * integrated graphics even though the support isn't actually there | 804 | * integrated graphics even though the support isn't actually there |
@@ -796,6 +822,8 @@ int i915_driver_unload(struct drm_device *dev) | |||
796 | if (dev->pdev->msi_enabled) | 822 | if (dev->pdev->msi_enabled) |
797 | pci_disable_msi(dev->pdev); | 823 | pci_disable_msi(dev->pdev); |
798 | 824 | ||
825 | i915_free_hws(dev); | ||
826 | |||
799 | if (dev_priv->mmio_map) | 827 | if (dev_priv->mmio_map) |
800 | drm_rmmap(dev, dev_priv->mmio_map); | 828 | drm_rmmap(dev, dev_priv->mmio_map); |
801 | 829 | ||