22,9 → 22,8 |
* |
*/ |
|
#include "drmP.h" |
#include "drm.h" |
#include "i915_drm.h" |
#include <drm/drmP.h> |
#include <drm/i915_drm.h> |
#include "i915_drv.h" |
#include "i915_trace.h" |
#include "intel_drv.h" |
33,6 → 32,220 |
#define AGP_USER_MEMORY (AGP_USER_TYPES) |
#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) |
|
/* PPGTT support for Sandybdrige/Gen6 and later */ |
static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, |
unsigned first_entry, |
unsigned num_entries) |
{ |
uint32_t *pt_vaddr; |
uint32_t scratch_pte; |
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; |
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; |
unsigned last_pte, i; |
|
scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr); |
scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC; |
|
pt_vaddr = AllocKernelSpace(4096); |
|
if(pt_vaddr != NULL) |
{ |
while (num_entries) |
{ |
last_pte = first_pte + num_entries; |
if (last_pte > I915_PPGTT_PT_ENTRIES) |
last_pte = I915_PPGTT_PT_ENTRIES; |
|
MapPage(pt_vaddr,ppgtt->pt_pages[act_pd], 3); |
|
for (i = first_pte; i < last_pte; i++) |
pt_vaddr[i] = scratch_pte; |
|
num_entries -= last_pte - first_pte; |
first_pte = 0; |
act_pd++; |
} |
FreeKernelSpace(pt_vaddr); |
}; |
} |
|
int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct i915_hw_ppgtt *ppgtt; |
unsigned first_pd_entry_in_global_pt; |
int i; |
int ret = -ENOMEM; |
|
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 |
* entries. For aliasing ppgtt support we just steal them at the end for |
* now. */ |
first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES; |
|
ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); |
if (!ppgtt) |
return ret; |
|
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; |
ppgtt->pt_pages = kzalloc(sizeof(dma_addr_t)*ppgtt->num_pd_entries, |
GFP_KERNEL); |
if (!ppgtt->pt_pages) |
goto err_ppgtt; |
|
for (i = 0; i < ppgtt->num_pd_entries; i++) { |
ppgtt->pt_pages[i] = AllocPage(); |
if (!ppgtt->pt_pages[i]) |
goto err_pt_alloc; |
} |
|
/* |
if (dev_priv->mm.gtt->needs_dmar) { |
ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) |
*ppgtt->num_pd_entries, |
GFP_KERNEL); |
if (!ppgtt->pt_dma_addr) |
goto err_pt_alloc; |
|
for (i = 0; i < ppgtt->num_pd_entries; i++) { |
dma_addr_t pt_addr; |
|
pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], |
0, 4096, |
PCI_DMA_BIDIRECTIONAL); |
|
if (pci_dma_mapping_error(dev->pdev, |
pt_addr)) { |
ret = -EIO; |
goto err_pd_pin; |
|
} |
ppgtt->pt_dma_addr[i] = pt_addr; |
} |
} |
*/ |
ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; |
|
i915_ppgtt_clear_range(ppgtt, 0, |
ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); |
|
ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(uint32_t); |
|
dev_priv->mm.aliasing_ppgtt = ppgtt; |
|
return 0; |
|
err_pd_pin: |
// if (ppgtt->pt_dma_addr) { |
// for (i--; i >= 0; i--) |
// pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], |
// 4096, PCI_DMA_BIDIRECTIONAL); |
// } |
err_pt_alloc: |
// kfree(ppgtt->pt_dma_addr); |
for (i = 0; i < ppgtt->num_pd_entries; i++) { |
if (ppgtt->pt_pages[i]) |
FreePage(ppgtt->pt_pages[i]); |
} |
kfree(ppgtt->pt_pages); |
err_ppgtt: |
kfree(ppgtt); |
|
return ret; |
} |
|
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) |
{ |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; |
int i; |
|
if (!ppgtt) |
return; |
|
// if (ppgtt->pt_dma_addr) { |
// for (i = 0; i < ppgtt->num_pd_entries; i++) |
// pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], |
// 4096, PCI_DMA_BIDIRECTIONAL); |
// } |
|
// kfree(ppgtt->pt_dma_addr); |
for (i = 0; i < ppgtt->num_pd_entries; i++) |
FreePage(ppgtt->pt_pages[i]); |
kfree(ppgtt->pt_pages); |
kfree(ppgtt); |
} |
|
static void i915_ppgtt_insert_sg_entries(struct i915_hw_ppgtt *ppgtt, |
const struct pagelist *pages, |
unsigned first_entry, |
uint32_t pte_flags) |
{ |
uint32_t *pt_vaddr, pte; |
unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; |
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; |
unsigned i, j; |
dma_addr_t page_addr; |
|
i = 0; |
|
pt_vaddr = AllocKernelSpace(4096); |
|
if( pt_vaddr != NULL) |
{ |
while (i < pages->nents) |
{ |
MapPage(pt_vaddr, ppgtt->pt_pages[act_pd], 3); |
|
for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++, i++) { |
page_addr = pages->page[i]; |
pte = GEN6_PTE_ADDR_ENCODE(page_addr); |
pt_vaddr[j] = pte | pte_flags; |
} |
|
first_pte = 0; |
act_pd++; |
} |
FreeKernelSpace(pt_vaddr); |
}; |
} |
|
void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, |
struct drm_i915_gem_object *obj, |
enum i915_cache_level cache_level) |
{ |
uint32_t pte_flags = GEN6_PTE_VALID; |
|
switch (cache_level) { |
case I915_CACHE_LLC_MLC: |
pte_flags |= GEN6_PTE_CACHE_LLC_MLC; |
break; |
case I915_CACHE_LLC: |
pte_flags |= GEN6_PTE_CACHE_LLC; |
break; |
case I915_CACHE_NONE: |
if (IS_HASWELL(obj->base.dev)) |
pte_flags |= HSW_PTE_UNCACHED; |
else |
pte_flags |= GEN6_PTE_UNCACHED; |
break; |
default: |
BUG(); |
} |
|
i915_ppgtt_insert_sg_entries(ppgtt, |
&obj->pages, |
obj->gtt_space->start >> PAGE_SHIFT, |
pte_flags); |
} |
|
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, |
struct drm_i915_gem_object *obj) |
{ |
i915_ppgtt_clear_range(ppgtt, |
obj->gtt_space->start >> PAGE_SHIFT, |
obj->base.size >> PAGE_SHIFT); |
} |
|
/* XXX kill agp_type! */ |
static unsigned int cache_level_to_agp_type(struct drm_device *dev, |
enum i915_cache_level cache_level) |
85,9 → 298,9 |
intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE, |
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); |
|
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { |
list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { |
i915_gem_clflush_object(obj); |
i915_gem_gtt_rebind_object(obj, obj->cache_level); |
i915_gem_gtt_bind_object(obj, obj->cache_level); |
} |
|
intel_gtt_chipset_flush(); |
94,57 → 307,41 |
} |
#endif |
|
int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) |
int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) |
{ |
struct drm_device *dev = obj->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level); |
int ret; |
if (obj->has_dma_mapping) |
return 0; |
|
// if (dev_priv->mm.gtt->needs_dmar) { |
// ret = intel_gtt_map_memory(obj->pages, |
// obj->base.size >> PAGE_SHIFT, |
// &obj->sg_list, |
// &obj->num_sg); |
// if (ret != 0) |
// return ret; |
// if (!dma_map_sg(&obj->base.dev->pdev->dev, |
// obj->pages->sgl, obj->pages->nents, |
// PCI_DMA_BIDIRECTIONAL)) |
// return -ENOSPC; |
|
// intel_gtt_insert_sg_entries(obj->sg_list, |
// obj->num_sg, |
// obj->gtt_space->start >> PAGE_SHIFT, |
// agp_type); |
// } else |
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, |
obj->base.size >> PAGE_SHIFT, |
obj->pages, |
agp_type); |
|
return 0; |
} |
|
void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj, |
void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, |
enum i915_cache_level cache_level) |
{ |
struct drm_device *dev = obj->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
unsigned int agp_type = cache_level_to_agp_type(dev, cache_level); |
|
// if (dev_priv->mm.gtt->needs_dmar) { |
// BUG_ON(!obj->sg_list); |
|
// intel_gtt_insert_sg_entries(obj->sg_list, |
// obj->num_sg, |
// obj->gtt_space->start >> PAGE_SHIFT, |
// agp_type); |
// } else |
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT, |
obj->base.size >> PAGE_SHIFT, |
obj->pages, |
intel_gtt_insert_sg_entries(&obj->pages, |
obj->gtt_space->start >> PAGE_SHIFT, |
agp_type); |
obj->has_global_gtt_mapping = 1; |
} |
|
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) |
{ |
intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, |
obj->base.size >> PAGE_SHIFT); |
|
obj->has_global_gtt_mapping = 0; |
} |
|
void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj) |
{ |
struct drm_device *dev = obj->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
bool interruptible; |
151,13 → 348,49 |
|
interruptible = do_idling(dev_priv); |
|
intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, |
obj->base.size >> PAGE_SHIFT); |
// if (!obj->has_dma_mapping) |
// dma_unmap_sg(&dev->pdev->dev, |
// obj->pages->sgl, obj->pages->nents, |
// PCI_DMA_BIDIRECTIONAL); |
|
if (obj->sg_list) { |
// intel_gtt_unmap_memory(obj->sg_list, obj->num_sg); |
obj->sg_list = NULL; |
undo_idling(dev_priv, interruptible); |
} |
|
undo_idling(dev_priv, interruptible); |
static void i915_gtt_color_adjust(struct drm_mm_node *node, |
unsigned long color, |
unsigned long *start, |
unsigned long *end) |
{ |
if (node->color != color) |
*start += 4096; |
|
if (!list_empty(&node->node_list)) { |
node = list_entry(node->node_list.next, |
struct drm_mm_node, |
node_list); |
if (node->allocated && node->color != color) |
*end -= 4096; |
} |
} |
|
void i915_gem_init_global_gtt(struct drm_device *dev, |
unsigned long start, |
unsigned long mappable_end, |
unsigned long end) |
{ |
drm_i915_private_t *dev_priv = dev->dev_private; |
|
/* Substract the guard page ... */ |
drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE); |
if (!HAS_LLC(dev)) |
dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust; |
|
dev_priv->mm.gtt_start = start; |
dev_priv->mm.gtt_mappable_end = mappable_end; |
dev_priv->mm.gtt_end = end; |
dev_priv->mm.gtt_total = end - start; |
dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start; |
|
/* ... but ensure that we clear the entire range. */ |
intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); |
} |