diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 139 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 16 |
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); | ||
1301 | cleanup_vga_switcheroo: | 1319 | cleanup_vga_switcheroo: |
1302 | vga_switcheroo_unregister_client(dev->pdev); | 1320 | vga_switcheroo_unregister_client(dev->pdev); |
1303 | cleanup_vga_client: | 1321 | cleanup_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 | ||
263 | struct 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 | |||
261 | enum no_fbc_reason { | 271 | enum 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 */ |
1250 | int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); | ||
1251 | void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); | ||
1252 | |||
1235 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); | 1253 | void i915_gem_restore_gtt_mappings(struct drm_device *dev); |
1236 | int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); | 1254 | int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); |
1237 | void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, | 1255 | void 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 */ | ||
33 | static 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 | |||
55 | int 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 | |||
130 | err_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 | } | ||
136 | err_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); | ||
143 | err_ppgtt: | ||
144 | kfree(ppgtt); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | void 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! */ |
33 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, | 172 | static 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 |