aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Widawsky <benjamin.widawsky@intel.com>2013-11-04 23:47:32 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-11-08 12:09:45 -0500
commit37aca44ad5b0fa30d4a9cd77b492b45f2b6a4643 (patch)
tree5c1ea3690a100e4aadbdd5904bf3180641227797 /drivers/gpu/drm
parentfbe5d36e7789827704b8f15cd99971f2615c0832 (diff)
drm/i915/bdw: PPGTT init & cleanup
Aside from the potential size increase of the PPGTT, the primary difference from previous hardware is the Page Directories are no longer carved out of the Global GTT. Note that the PDE allocation is done as a 8MB contiguous allocation, this needs to be eventually fixed (since driver reloading will be a pain otherwise). Also, this will be a no-go for real PPGTT support. v2: Move vtable initialization v3: Resolve conflicts due to patch series reordering. v4: Rebase on top of the address space refactoring of the PPGTT support. Drop Imre's r-b tag for v2, too outdated by now. v5: Free the correct amount of memory, "get_order takes size not a page count." (Imre) Signed-off-by: Ben Widawsky <ben@bwidawsk.net> Reviewed-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h19
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c123
2 files changed, 137 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 12cc0c51c73d..99695c517de7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -573,10 +573,21 @@ struct i915_gtt {
573struct i915_hw_ppgtt { 573struct i915_hw_ppgtt {
574 struct i915_address_space base; 574 struct i915_address_space base;
575 unsigned num_pd_entries; 575 unsigned num_pd_entries;
576 struct page **pt_pages; 576 union {
577 uint32_t pd_offset; 577 struct page **pt_pages;
578 dma_addr_t *pt_dma_addr; 578 struct page *gen8_pt_pages;
579 579 };
580 struct page *pd_pages;
581 int num_pd_pages;
582 int num_pt_pages;
583 union {
584 uint32_t pd_offset;
585 dma_addr_t pd_dma_addr[4];
586 };
587 union {
588 dma_addr_t *pt_dma_addr;
589 dma_addr_t *gen8_pt_dma_addr[4];
590 };
580 int (*enable)(struct drm_device *dev); 591 int (*enable)(struct drm_device *dev);
581}; 592};
582 593
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 47765d26f15a..5704d6437c64 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -31,6 +31,7 @@
31#define GEN6_PPGTT_PD_ENTRIES 512 31#define GEN6_PPGTT_PD_ENTRIES 512
32#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t)) 32#define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
33typedef uint64_t gen8_gtt_pte_t; 33typedef uint64_t gen8_gtt_pte_t;
34typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
34 35
35/* PPGTT stuff */ 36/* PPGTT stuff */
36#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) 37#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
@@ -58,6 +59,9 @@ typedef uint64_t gen8_gtt_pte_t;
58#define HSW_WB_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0xb) 59#define HSW_WB_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0xb)
59#define HSW_WT_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x6) 60#define HSW_WT_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x6)
60 61
62#define GEN8_PDES_PER_PAGE (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
63#define GEN8_LEGACY_PDPS 4
64
61#define PPAT_UNCACHED_INDEX (_PAGE_PWT | _PAGE_PCD) 65#define PPAT_UNCACHED_INDEX (_PAGE_PWT | _PAGE_PCD)
62#define PPAT_CACHED_PDE_INDEX 0 /* WB LLC */ 66#define PPAT_CACHED_PDE_INDEX 0 /* WB LLC */
63#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */ 67#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */
@@ -177,6 +181,123 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
177 return pte; 181 return pte;
178} 182}
179 183
184static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
185{
186 struct i915_hw_ppgtt *ppgtt =
187 container_of(vm, struct i915_hw_ppgtt, base);
188 int i, j;
189
190 for (i = 0; i < ppgtt->num_pd_pages ; i++) {
191 if (ppgtt->pd_dma_addr[i]) {
192 pci_unmap_page(ppgtt->base.dev->pdev,
193 ppgtt->pd_dma_addr[i],
194 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
195
196 for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
197 dma_addr_t addr = ppgtt->gen8_pt_dma_addr[i][j];
198 if (addr)
199 pci_unmap_page(ppgtt->base.dev->pdev,
200 addr,
201 PAGE_SIZE,
202 PCI_DMA_BIDIRECTIONAL);
203
204 }
205 }
206 kfree(ppgtt->gen8_pt_dma_addr[i]);
207 }
208
209 __free_pages(ppgtt->gen8_pt_pages, ppgtt->num_pt_pages << PAGE_SHIFT);
210 __free_pages(ppgtt->pd_pages, ppgtt->num_pd_pages << PAGE_SHIFT);
211}
212
213/**
214 * GEN8 legacy ppgtt programming is accomplished through 4 PDP registers with a
215 * net effect resembling a 2-level page table in normal x86 terms. Each PDP
216 * represents 1GB of memory
217 * 4 * 512 * 512 * 4096 = 4GB legacy 32b address space.
218 *
219 * TODO: Do something with the size parameter
220 **/
221static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
222{
223 struct page *pt_pages;
224 int i, j, ret = -ENOMEM;
225 const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
226 const int num_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
227
228 if (size % (1<<30))
229 DRM_INFO("Pages will be wasted unless GTT size (%llu) is divisible by 1GB\n", size);
230
231 /* FIXME: split allocation into smaller pieces. For now we only ever do
232 * this once, but with full PPGTT, the multiple contiguous allocations
233 * will be bad.
234 */
235 ppgtt->pd_pages = alloc_pages(GFP_KERNEL, get_order(max_pdp << PAGE_SHIFT));
236 if (!ppgtt->pd_pages)
237 return -ENOMEM;
238
239 pt_pages = alloc_pages(GFP_KERNEL, get_order(num_pt_pages << PAGE_SHIFT));
240 if (!pt_pages) {
241 __free_pages(ppgtt->pd_pages, get_order(max_pdp << PAGE_SHIFT));
242 return -ENOMEM;
243 }
244
245 ppgtt->gen8_pt_pages = pt_pages;
246 ppgtt->num_pd_pages = 1 << get_order(max_pdp << PAGE_SHIFT);
247 ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT);
248 ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
249 ppgtt->base.clear_range = NULL;
250 ppgtt->base.insert_entries = NULL;
251 ppgtt->base.cleanup = gen8_ppgtt_cleanup;
252
253 BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
254
255 /*
256 * - Create a mapping for the page directories.
257 * - For each page directory:
258 * allocate space for page table mappings.
259 * map each page table
260 */
261 for (i = 0; i < max_pdp; i++) {
262 dma_addr_t temp;
263 temp = pci_map_page(ppgtt->base.dev->pdev,
264 &ppgtt->pd_pages[i], 0,
265 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
266 if (pci_dma_mapping_error(ppgtt->base.dev->pdev, temp))
267 goto err_out;
268
269 ppgtt->pd_dma_addr[i] = temp;
270
271 ppgtt->gen8_pt_dma_addr[i] = kmalloc(sizeof(dma_addr_t) * GEN8_PDES_PER_PAGE, GFP_KERNEL);
272 if (!ppgtt->gen8_pt_dma_addr[i])
273 goto err_out;
274
275 for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
276 struct page *p = &pt_pages[i * GEN8_PDES_PER_PAGE + j];
277 temp = pci_map_page(ppgtt->base.dev->pdev,
278 p, 0, PAGE_SIZE,
279 PCI_DMA_BIDIRECTIONAL);
280
281 if (pci_dma_mapping_error(ppgtt->base.dev->pdev, temp))
282 goto err_out;
283
284 ppgtt->gen8_pt_dma_addr[i][j] = temp;
285 }
286 }
287
288 DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n",
289 ppgtt->num_pd_pages, ppgtt->num_pd_pages - max_pdp);
290 DRM_DEBUG_DRIVER("Allocated %d pages for page tables (%lld wasted)\n",
291 ppgtt->num_pt_pages,
292 (ppgtt->num_pt_pages - num_pt_pages) +
293 size % (1<<30));
294 return -ENOSYS; /* Not ready yet */
295
296err_out:
297 ppgtt->base.cleanup(&ppgtt->base);
298 return ret;
299}
300
180static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt) 301static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
181{ 302{
182 struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private; 303 struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
@@ -430,7 +551,7 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
430 if (INTEL_INFO(dev)->gen < 8) 551 if (INTEL_INFO(dev)->gen < 8)
431 ret = gen6_ppgtt_init(ppgtt); 552 ret = gen6_ppgtt_init(ppgtt);
432 else if (IS_GEN8(dev)) 553 else if (IS_GEN8(dev))
433 ret = -ENOSYS; 554 ret = gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
434 else 555 else
435 BUG(); 556 BUG();
436 557