aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c41
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h18
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c139
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h16
4 files changed, 203 insertions, 11 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index dfef9569f2a..039fbf4fae1 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1196,22 +1196,39 @@ static int i915_load_gem_init(struct drm_device *dev)
1196 /* Basic memrange allocator for stolen space */ 1196 /* Basic memrange allocator for stolen space */
1197 drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size); 1197 drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
1198 1198
1199 /* Let GEM Manage all of the aperture. 1199 if (HAS_ALIASING_PPGTT(dev)) {
1200 * 1200 /* PPGTT pdes are stolen from global gtt ptes, so shrink the
1201 * However, leave one page at the end still bound to the scratch page. 1201 * aperture accordingly when using aliasing ppgtt. */
1202 * There are a number of places where the hardware apparently 1202 gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
1203 * prefetches past the end of the object, and we've seen multiple 1203 /* For paranoia keep the guard page in between. */
1204 * hangs with the GPU head pointer stuck in a batchbuffer bound 1204 gtt_size -= PAGE_SIZE;
1205 * at the last page of the aperture. One page should be enough to 1205
1206 * keep any prefetching inside of the aperture. 1206 i915_gem_do_init(dev, 0, mappable_size, gtt_size);
1207 */ 1207
1208 i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE); 1208 ret = i915_gem_init_aliasing_ppgtt(dev);
1209 if (ret)
1210 return ret;
1211 } else {
1212 /* Let GEM Manage all of the aperture.
1213 *
1214 * However, leave one page at the end still bound to the scratch
1215 * page. There are a number of places where the hardware
1216 * apparently prefetches past the end of the object, and we've
1217 * seen multiple hangs with the GPU head pointer stuck in a
1218 * batchbuffer bound at the last page of the aperture. One page
1219 * should be enough to keep any prefetching inside of the
1220 * aperture.
1221 */
1222 i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
1223 }
1209 1224
1210 mutex_lock(&dev->struct_mutex); 1225 mutex_lock(&dev->struct_mutex);
1211 ret = i915_gem_init_hw(dev); 1226 ret = i915_gem_init_hw(dev);
1212 mutex_unlock(&dev->struct_mutex); 1227 mutex_unlock(&dev->struct_mutex);
1213 if (ret) 1228 if (ret) {
1229 i915_gem_cleanup_aliasing_ppgtt(dev);
1214 return ret; 1230 return ret;
1231 }
1215 1232
1216 /* Try to set up FBC with a reasonable compressed buffer size */ 1233 /* Try to set up FBC with a reasonable compressed buffer size */
1217 if (I915_HAS_FBC(dev) && i915_powersave) { 1234 if (I915_HAS_FBC(dev) && i915_powersave) {
@@ -1298,6 +1315,7 @@ cleanup_gem:
1298 mutex_lock(&dev->struct_mutex); 1315 mutex_lock(&dev->struct_mutex);
1299 i915_gem_cleanup_ringbuffer(dev); 1316 i915_gem_cleanup_ringbuffer(dev);
1300 mutex_unlock(&dev->struct_mutex); 1317 mutex_unlock(&dev->struct_mutex);
1318 i915_gem_cleanup_aliasing_ppgtt(dev);
1301cleanup_vga_switcheroo: 1319cleanup_vga_switcheroo:
1302 vga_switcheroo_unregister_client(dev->pdev); 1320 vga_switcheroo_unregister_client(dev->pdev);
1303cleanup_vga_client: 1321cleanup_vga_client:
@@ -2184,6 +2202,7 @@ int i915_driver_unload(struct drm_device *dev)
2184 i915_gem_free_all_phys_object(dev); 2202 i915_gem_free_all_phys_object(dev);
2185 i915_gem_cleanup_ringbuffer(dev); 2203 i915_gem_cleanup_ringbuffer(dev);
2186 mutex_unlock(&dev->struct_mutex); 2204 mutex_unlock(&dev->struct_mutex);
2205 i915_gem_cleanup_aliasing_ppgtt(dev);
2187 if (I915_HAS_FBC(dev) && i915_powersave) 2206 if (I915_HAS_FBC(dev) && i915_powersave)
2188 i915_cleanup_compression(dev); 2207 i915_cleanup_compression(dev);
2189 drm_mm_takedown(&dev_priv->mm.stolen); 2208 drm_mm_takedown(&dev_priv->mm.stolen);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 28740bc0200..03a9e49fe93 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -258,6 +258,16 @@ struct intel_device_info {
258 u8 has_llc:1; 258 u8 has_llc:1;
259}; 259};
260 260
261#define I915_PPGTT_PD_ENTRIES 512
262#define I915_PPGTT_PT_ENTRIES 1024
263struct i915_hw_ppgtt {
264 unsigned num_pd_entries;
265 struct page **pt_pages;
266 uint32_t pd_offset;
267 dma_addr_t *pt_dma_addr;
268 dma_addr_t scratch_page_dma_addr;
269};
270
261enum no_fbc_reason { 271enum no_fbc_reason {
262 FBC_NO_OUTPUT, /* no outputs enabled to compress */ 272 FBC_NO_OUTPUT, /* no outputs enabled to compress */
263 FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */ 273 FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
@@ -578,6 +588,9 @@ typedef struct drm_i915_private {
578 struct io_mapping *gtt_mapping; 588 struct io_mapping *gtt_mapping;
579 int gtt_mtrr; 589 int gtt_mtrr;
580 590
591 /** PPGTT used for aliasing the PPGTT with the GTT */
592 struct i915_hw_ppgtt *aliasing_ppgtt;
593
581 struct shrinker inactive_shrinker; 594 struct shrinker inactive_shrinker;
582 595
583 /** 596 /**
@@ -973,6 +986,8 @@ struct drm_i915_file_private {
973#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc) 986#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc)
974#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) 987#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
975 988
989#define HAS_ALIASING_PPGTT(dev) (INTEL_INFO(dev)->gen >=6)
990
976#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay) 991#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay)
977#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical) 992#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical)
978 993
@@ -1232,6 +1247,9 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
1232 enum i915_cache_level cache_level); 1247 enum i915_cache_level cache_level);
1233 1248
1234/* i915_gem_gtt.c */ 1249/* i915_gem_gtt.c */
1250int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
1251void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
1252
1235void i915_gem_restore_gtt_mappings(struct drm_device *dev); 1253void i915_gem_restore_gtt_mappings(struct drm_device *dev);
1236int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); 1254int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
1237void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, 1255void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 11bddd5a5a6..f408f8c710d 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -29,6 +29,145 @@
29#include "i915_trace.h" 29#include "i915_trace.h"
30#include "intel_drv.h" 30#include "intel_drv.h"
31 31
32/* PPGTT support for Sandybdrige/Gen6 and later */
33static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
34 unsigned first_entry,
35 unsigned num_entries)
36{
37 int i, j;
38 uint32_t *pt_vaddr;
39 uint32_t scratch_pte;
40
41 scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr);
42 scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC;
43
44 for (i = 0; i < ppgtt->num_pd_entries; i++) {
45 pt_vaddr = kmap_atomic(ppgtt->pt_pages[i]);
46
47 for (j = 0; j < I915_PPGTT_PT_ENTRIES; j++)
48 pt_vaddr[j] = scratch_pte;
49
50 kunmap_atomic(pt_vaddr);
51 }
52
53}
54
55int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
56{
57 struct drm_i915_private *dev_priv = dev->dev_private;
58 struct i915_hw_ppgtt *ppgtt;
59 uint32_t pd_entry;
60 unsigned first_pd_entry_in_global_pt;
61 uint32_t __iomem *pd_addr;
62 int i;
63 int ret = -ENOMEM;
64
65 /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
66 * entries. For aliasing ppgtt support we just steal them at the end for
67 * now. */
68 first_pd_entry_in_global_pt = 512*1024 - I915_PPGTT_PD_ENTRIES;
69
70 ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
71 if (!ppgtt)
72 return ret;
73
74 ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
75 ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries,
76 GFP_KERNEL);
77 if (!ppgtt->pt_pages)
78 goto err_ppgtt;
79
80 for (i = 0; i < ppgtt->num_pd_entries; i++) {
81 ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
82 if (!ppgtt->pt_pages[i])
83 goto err_pt_alloc;
84 }
85
86 if (dev_priv->mm.gtt->needs_dmar) {
87 ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t)
88 *ppgtt->num_pd_entries,
89 GFP_KERNEL);
90 if (!ppgtt->pt_dma_addr)
91 goto err_pt_alloc;
92 }
93
94 pd_addr = dev_priv->mm.gtt->gtt + first_pd_entry_in_global_pt;
95 for (i = 0; i < ppgtt->num_pd_entries; i++) {
96 dma_addr_t pt_addr;
97 if (dev_priv->mm.gtt->needs_dmar) {
98 pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i],
99 0, 4096,
100 PCI_DMA_BIDIRECTIONAL);
101
102 if (pci_dma_mapping_error(dev->pdev,
103 pt_addr)) {
104 ret = -EIO;
105 goto err_pd_pin;
106
107 }
108 ppgtt->pt_dma_addr[i] = pt_addr;
109 } else
110 pt_addr = page_to_phys(ppgtt->pt_pages[i]);
111
112 pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr);
113 pd_entry |= GEN6_PDE_VALID;
114
115 writel(pd_entry, pd_addr + i);
116 }
117 readl(pd_addr);
118
119 ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma;
120
121 i915_ppgtt_clear_range(ppgtt, 0,
122 ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES);
123
124 ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(uint32_t);
125
126 dev_priv->mm.aliasing_ppgtt = ppgtt;
127
128 return 0;
129
130err_pd_pin:
131 if (ppgtt->pt_dma_addr) {
132 for (i--; i >= 0; i--)
133 pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
134 4096, PCI_DMA_BIDIRECTIONAL);
135 }
136err_pt_alloc:
137 kfree(ppgtt->pt_dma_addr);
138 for (i = 0; i < ppgtt->num_pd_entries; i++) {
139 if (ppgtt->pt_pages[i])
140 __free_page(ppgtt->pt_pages[i]);
141 }
142 kfree(ppgtt->pt_pages);
143err_ppgtt:
144 kfree(ppgtt);
145
146 return ret;
147}
148
149void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
150{
151 struct drm_i915_private *dev_priv = dev->dev_private;
152 struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
153 int i;
154
155 if (!ppgtt)
156 return;
157
158 if (ppgtt->pt_dma_addr) {
159 for (i = 0; i < ppgtt->num_pd_entries; i++)
160 pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
161 4096, PCI_DMA_BIDIRECTIONAL);
162 }
163
164 kfree(ppgtt->pt_dma_addr);
165 for (i = 0; i < ppgtt->num_pd_entries; i++)
166 __free_page(ppgtt->pt_pages[i]);
167 kfree(ppgtt->pt_pages);
168 kfree(ppgtt);
169}
170
32/* XXX kill agp_type! */ 171/* XXX kill agp_type! */
33static unsigned int cache_level_to_agp_type(struct drm_device *dev, 172static unsigned int cache_level_to_agp_type(struct drm_device *dev,
34 enum i915_cache_level cache_level) 173 enum i915_cache_level cache_level)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 89816fe3f9d..92eb404d063 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -92,6 +92,22 @@
92#define GEN6_GRDOM_MEDIA (1 << 2) 92#define GEN6_GRDOM_MEDIA (1 << 2)
93#define GEN6_GRDOM_BLT (1 << 3) 93#define GEN6_GRDOM_BLT (1 << 3)
94 94
95/* PPGTT stuff */
96#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
97
98#define GEN6_PDE_VALID (1 << 0)
99#define GEN6_PDE_LARGE_PAGE (2 << 0) /* use 32kb pages */
100/* gen6+ has bit 11-4 for physical addr bit 39-32 */
101#define GEN6_PDE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
102
103#define GEN6_PTE_VALID (1 << 0)
104#define GEN6_PTE_UNCACHED (1 << 1)
105#define GEN6_PTE_CACHE_LLC (2 << 1)
106#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
107#define GEN6_PTE_CACHE_BITS (3 << 1)
108#define GEN6_PTE_GFDT (1 << 3)
109#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
110
95/* VGA stuff */ 111/* VGA stuff */
96 112
97#define VGA_ST01_MDA 0x3ba 113#define VGA_ST01_MDA 0x3ba