|
@@ -23,10 +23,14 @@
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+#include <linux/log2.h>
|
|
|
|
+#include <linux/random.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/stop_machine.h>
|
|
#include <linux/stop_machine.h>
|
|
|
|
+
|
|
#include <drm/drmP.h>
|
|
#include <drm/drmP.h>
|
|
#include <drm/i915_drm.h>
|
|
#include <drm/i915_drm.h>
|
|
|
|
+
|
|
#include "i915_drv.h"
|
|
#include "i915_drv.h"
|
|
#include "i915_vgpu.h"
|
|
#include "i915_vgpu.h"
|
|
#include "i915_trace.h"
|
|
#include "i915_trace.h"
|
|
@@ -99,12 +103,29 @@
|
|
static int
|
|
static int
|
|
i915_get_ggtt_vma_pages(struct i915_vma *vma);
|
|
i915_get_ggtt_vma_pages(struct i915_vma *vma);
|
|
|
|
|
|
-const struct i915_ggtt_view i915_ggtt_view_normal = {
|
|
|
|
- .type = I915_GGTT_VIEW_NORMAL,
|
|
|
|
-};
|
|
|
|
-const struct i915_ggtt_view i915_ggtt_view_rotated = {
|
|
|
|
- .type = I915_GGTT_VIEW_ROTATED,
|
|
|
|
-};
|
|
|
|
|
|
+static void gen6_ggtt_invalidate(struct drm_i915_private *dev_priv)
|
|
|
|
+{
|
|
|
|
+ /* Note that as an uncached mmio write, this should flush the
|
|
|
|
+ * WCB of the writes into the GGTT before it triggers the invalidate.
|
|
|
|
+ */
|
|
|
|
+ I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void guc_ggtt_invalidate(struct drm_i915_private *dev_priv)
|
|
|
|
+{
|
|
|
|
+ gen6_ggtt_invalidate(dev_priv);
|
|
|
|
+ I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void gmch_ggtt_invalidate(struct drm_i915_private *dev_priv)
|
|
|
|
+{
|
|
|
|
+ intel_gtt_chipset_flush();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void i915_ggtt_invalidate(struct drm_i915_private *i915)
|
|
|
|
+{
|
|
|
|
+ i915->ggtt.invalidate(i915);
|
|
|
|
+}
|
|
|
|
|
|
int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
|
|
int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
|
|
int enable_ppgtt)
|
|
int enable_ppgtt)
|
|
@@ -329,7 +350,7 @@ static int __setup_page_dma(struct drm_i915_private *dev_priv,
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
p->daddr = dma_map_page(kdev,
|
|
p->daddr = dma_map_page(kdev,
|
|
- p->page, 0, 4096, PCI_DMA_BIDIRECTIONAL);
|
|
|
|
|
|
+ p->page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
|
|
|
|
|
if (dma_mapping_error(kdev, p->daddr)) {
|
|
if (dma_mapping_error(kdev, p->daddr)) {
|
|
__free_page(p->page);
|
|
__free_page(p->page);
|
|
@@ -353,7 +374,7 @@ static void cleanup_page_dma(struct drm_i915_private *dev_priv,
|
|
if (WARN_ON(!p->page))
|
|
if (WARN_ON(!p->page))
|
|
return;
|
|
return;
|
|
|
|
|
|
- dma_unmap_page(&pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL);
|
|
|
|
|
|
+ dma_unmap_page(&pdev->dev, p->daddr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
|
__free_page(p->page);
|
|
__free_page(p->page);
|
|
memset(p, 0, sizeof(*p));
|
|
memset(p, 0, sizeof(*p));
|
|
}
|
|
}
|
|
@@ -626,10 +647,10 @@ static void gen8_initialize_pml4(struct i915_address_space *vm,
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-gen8_setup_page_directory(struct i915_hw_ppgtt *ppgtt,
|
|
|
|
- struct i915_page_directory_pointer *pdp,
|
|
|
|
- struct i915_page_directory *pd,
|
|
|
|
- int index)
|
|
|
|
|
|
+gen8_setup_pdpe(struct i915_hw_ppgtt *ppgtt,
|
|
|
|
+ struct i915_page_directory_pointer *pdp,
|
|
|
|
+ struct i915_page_directory *pd,
|
|
|
|
+ int index)
|
|
{
|
|
{
|
|
gen8_ppgtt_pdpe_t *page_directorypo;
|
|
gen8_ppgtt_pdpe_t *page_directorypo;
|
|
|
|
|
|
@@ -642,10 +663,10 @@ gen8_setup_page_directory(struct i915_hw_ppgtt *ppgtt,
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-gen8_setup_page_directory_pointer(struct i915_hw_ppgtt *ppgtt,
|
|
|
|
- struct i915_pml4 *pml4,
|
|
|
|
- struct i915_page_directory_pointer *pdp,
|
|
|
|
- int index)
|
|
|
|
|
|
+gen8_setup_pml4e(struct i915_hw_ppgtt *ppgtt,
|
|
|
|
+ struct i915_pml4 *pml4,
|
|
|
|
+ struct i915_page_directory_pointer *pdp,
|
|
|
|
+ int index)
|
|
{
|
|
{
|
|
gen8_ppgtt_pml4e_t *pagemap = kmap_px(pml4);
|
|
gen8_ppgtt_pml4e_t *pagemap = kmap_px(pml4);
|
|
|
|
|
|
@@ -793,9 +814,6 @@ static bool gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
|
|
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
|
|
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
|
|
struct i915_page_directory *pd;
|
|
struct i915_page_directory *pd;
|
|
uint64_t pdpe;
|
|
uint64_t pdpe;
|
|
- gen8_ppgtt_pdpe_t *pdpe_vaddr;
|
|
|
|
- gen8_ppgtt_pdpe_t scratch_pdpe =
|
|
|
|
- gen8_pdpe_encode(px_dma(vm->scratch_pd), I915_CACHE_LLC);
|
|
|
|
|
|
|
|
gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
|
|
gen8_for_each_pdpe(pd, pdp, start, length, pdpe) {
|
|
if (WARN_ON(!pdp->page_directory[pdpe]))
|
|
if (WARN_ON(!pdp->page_directory[pdpe]))
|
|
@@ -803,11 +821,7 @@ static bool gen8_ppgtt_clear_pdp(struct i915_address_space *vm,
|
|
|
|
|
|
if (gen8_ppgtt_clear_pd(vm, pd, start, length)) {
|
|
if (gen8_ppgtt_clear_pd(vm, pd, start, length)) {
|
|
__clear_bit(pdpe, pdp->used_pdpes);
|
|
__clear_bit(pdpe, pdp->used_pdpes);
|
|
- if (USES_FULL_48BIT_PPGTT(dev_priv)) {
|
|
|
|
- pdpe_vaddr = kmap_px(pdp);
|
|
|
|
- pdpe_vaddr[pdpe] = scratch_pdpe;
|
|
|
|
- kunmap_px(ppgtt, pdpe_vaddr);
|
|
|
|
- }
|
|
|
|
|
|
+ gen8_setup_pdpe(ppgtt, pdp, vm->scratch_pd, pdpe);
|
|
free_pd(vm->i915, pd);
|
|
free_pd(vm->i915, pd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -832,9 +846,6 @@ static void gen8_ppgtt_clear_pml4(struct i915_address_space *vm,
|
|
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
|
|
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
|
|
struct i915_page_directory_pointer *pdp;
|
|
struct i915_page_directory_pointer *pdp;
|
|
uint64_t pml4e;
|
|
uint64_t pml4e;
|
|
- gen8_ppgtt_pml4e_t *pml4e_vaddr;
|
|
|
|
- gen8_ppgtt_pml4e_t scratch_pml4e =
|
|
|
|
- gen8_pml4e_encode(px_dma(vm->scratch_pdp), I915_CACHE_LLC);
|
|
|
|
|
|
|
|
GEM_BUG_ON(!USES_FULL_48BIT_PPGTT(vm->i915));
|
|
GEM_BUG_ON(!USES_FULL_48BIT_PPGTT(vm->i915));
|
|
|
|
|
|
@@ -844,9 +855,7 @@ static void gen8_ppgtt_clear_pml4(struct i915_address_space *vm,
|
|
|
|
|
|
if (gen8_ppgtt_clear_pdp(vm, pdp, start, length)) {
|
|
if (gen8_ppgtt_clear_pdp(vm, pdp, start, length)) {
|
|
__clear_bit(pml4e, pml4->used_pml4es);
|
|
__clear_bit(pml4e, pml4->used_pml4es);
|
|
- pml4e_vaddr = kmap_px(pml4);
|
|
|
|
- pml4e_vaddr[pml4e] = scratch_pml4e;
|
|
|
|
- kunmap_px(ppgtt, pml4e_vaddr);
|
|
|
|
|
|
+ gen8_setup_pml4e(ppgtt, pml4, vm->scratch_pdp, pml4e);
|
|
free_pdp(vm->i915, pdp);
|
|
free_pdp(vm->i915, pdp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1366,7 +1375,7 @@ static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
|
|
|
|
|
|
kunmap_px(ppgtt, page_directory);
|
|
kunmap_px(ppgtt, page_directory);
|
|
__set_bit(pdpe, pdp->used_pdpes);
|
|
__set_bit(pdpe, pdp->used_pdpes);
|
|
- gen8_setup_page_directory(ppgtt, pdp, pd, pdpe);
|
|
|
|
|
|
+ gen8_setup_pdpe(ppgtt, pdp, pd, pdpe);
|
|
}
|
|
}
|
|
|
|
|
|
free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
|
|
free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
|
|
@@ -1425,7 +1434,7 @@ static int gen8_alloc_va_range_4lvl(struct i915_address_space *vm,
|
|
if (ret)
|
|
if (ret)
|
|
goto err_out;
|
|
goto err_out;
|
|
|
|
|
|
- gen8_setup_page_directory_pointer(ppgtt, pml4, pdp, pml4e);
|
|
|
|
|
|
+ gen8_setup_pml4e(ppgtt, pml4, pdp, pml4e);
|
|
}
|
|
}
|
|
|
|
|
|
bitmap_or(pml4->used_pml4es, new_pdps, pml4->used_pml4es,
|
|
bitmap_or(pml4->used_pml4es, new_pdps, pml4->used_pml4es,
|
|
@@ -2044,7 +2053,6 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
|
|
struct i915_address_space *vm = &ppgtt->base;
|
|
struct i915_address_space *vm = &ppgtt->base;
|
|
struct drm_i915_private *dev_priv = ppgtt->base.i915;
|
|
struct drm_i915_private *dev_priv = ppgtt->base.i915;
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
- bool retried = false;
|
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
/* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
|
|
/* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
|
|
@@ -2057,29 +2065,14 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
-alloc:
|
|
|
|
- ret = drm_mm_insert_node_in_range_generic(&ggtt->base.mm, &ppgtt->node,
|
|
|
|
- GEN6_PD_SIZE, GEN6_PD_ALIGN,
|
|
|
|
- I915_COLOR_UNEVICTABLE,
|
|
|
|
- 0, ggtt->base.total,
|
|
|
|
- DRM_MM_TOPDOWN);
|
|
|
|
- if (ret == -ENOSPC && !retried) {
|
|
|
|
- ret = i915_gem_evict_something(&ggtt->base,
|
|
|
|
- GEN6_PD_SIZE, GEN6_PD_ALIGN,
|
|
|
|
- I915_COLOR_UNEVICTABLE,
|
|
|
|
- 0, ggtt->base.total,
|
|
|
|
- 0);
|
|
|
|
- if (ret)
|
|
|
|
- goto err_out;
|
|
|
|
-
|
|
|
|
- retried = true;
|
|
|
|
- goto alloc;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ ret = i915_gem_gtt_insert(&ggtt->base, &ppgtt->node,
|
|
|
|
+ GEN6_PD_SIZE, GEN6_PD_ALIGN,
|
|
|
|
+ I915_COLOR_UNEVICTABLE,
|
|
|
|
+ 0, ggtt->base.total,
|
|
|
|
+ PIN_HIGH);
|
|
if (ret)
|
|
if (ret)
|
|
goto err_out;
|
|
goto err_out;
|
|
|
|
|
|
-
|
|
|
|
if (ppgtt->node.start < ggtt->mappable_end)
|
|
if (ppgtt->node.start < ggtt->mappable_end)
|
|
DRM_DEBUG("Forced to use aperture for PDEs\n");
|
|
DRM_DEBUG("Forced to use aperture for PDEs\n");
|
|
|
|
|
|
@@ -2267,6 +2260,27 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv,
|
|
return ppgtt;
|
|
return ppgtt;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void i915_ppgtt_close(struct i915_address_space *vm)
|
|
|
|
+{
|
|
|
|
+ struct list_head *phases[] = {
|
|
|
|
+ &vm->active_list,
|
|
|
|
+ &vm->inactive_list,
|
|
|
|
+ &vm->unbound_list,
|
|
|
|
+ NULL,
|
|
|
|
+ }, **phase;
|
|
|
|
+
|
|
|
|
+ GEM_BUG_ON(vm->closed);
|
|
|
|
+ vm->closed = true;
|
|
|
|
+
|
|
|
|
+ for (phase = phases; *phase; phase++) {
|
|
|
|
+ struct i915_vma *vma, *vn;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_safe(vma, vn, *phase, vm_link)
|
|
|
|
+ if (!i915_vma_is_closed(vma))
|
|
|
|
+ i915_vma_close(vma);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
void i915_ppgtt_release(struct kref *kref)
|
|
void i915_ppgtt_release(struct kref *kref)
|
|
{
|
|
{
|
|
struct i915_hw_ppgtt *ppgtt =
|
|
struct i915_hw_ppgtt *ppgtt =
|
|
@@ -2331,16 +2345,6 @@ void i915_check_and_clear_faults(struct drm_i915_private *dev_priv)
|
|
POSTING_READ(RING_FAULT_REG(dev_priv->engine[RCS]));
|
|
POSTING_READ(RING_FAULT_REG(dev_priv->engine[RCS]));
|
|
}
|
|
}
|
|
|
|
|
|
-static void i915_ggtt_flush(struct drm_i915_private *dev_priv)
|
|
|
|
-{
|
|
|
|
- if (INTEL_INFO(dev_priv)->gen < 6) {
|
|
|
|
- intel_gtt_chipset_flush();
|
|
|
|
- } else {
|
|
|
|
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
|
|
|
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv)
|
|
void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv)
|
|
{
|
|
{
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
@@ -2355,7 +2359,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv)
|
|
|
|
|
|
ggtt->base.clear_range(&ggtt->base, ggtt->base.start, ggtt->base.total);
|
|
ggtt->base.clear_range(&ggtt->base, ggtt->base.start, ggtt->base.total);
|
|
|
|
|
|
- i915_ggtt_flush(dev_priv);
|
|
|
|
|
|
+ i915_ggtt_invalidate(dev_priv);
|
|
}
|
|
}
|
|
|
|
|
|
int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
|
|
int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
|
|
@@ -2394,15 +2398,13 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm,
|
|
enum i915_cache_level level,
|
|
enum i915_cache_level level,
|
|
u32 unused)
|
|
u32 unused)
|
|
{
|
|
{
|
|
- struct drm_i915_private *dev_priv = vm->i915;
|
|
|
|
|
|
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
|
gen8_pte_t __iomem *pte =
|
|
gen8_pte_t __iomem *pte =
|
|
- (gen8_pte_t __iomem *)dev_priv->ggtt.gsm +
|
|
|
|
- (offset >> PAGE_SHIFT);
|
|
|
|
|
|
+ (gen8_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
|
|
|
|
|
|
gen8_set_pte(pte, gen8_pte_encode(addr, level));
|
|
gen8_set_pte(pte, gen8_pte_encode(addr, level));
|
|
|
|
|
|
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
|
|
|
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
|
|
|
|
|
+ ggtt->invalidate(vm->i915);
|
|
}
|
|
}
|
|
|
|
|
|
static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
|
|
static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
|
|
@@ -2410,7 +2412,6 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
|
|
uint64_t start,
|
|
uint64_t start,
|
|
enum i915_cache_level level, u32 unused)
|
|
enum i915_cache_level level, u32 unused)
|
|
{
|
|
{
|
|
- struct drm_i915_private *dev_priv = vm->i915;
|
|
|
|
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
|
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
|
struct sgt_iter sgt_iter;
|
|
struct sgt_iter sgt_iter;
|
|
gen8_pte_t __iomem *gtt_entries;
|
|
gen8_pte_t __iomem *gtt_entries;
|
|
@@ -2439,8 +2440,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
|
|
* want to flush the TLBs only after we're certain all the PTE updates
|
|
* want to flush the TLBs only after we're certain all the PTE updates
|
|
* have finished.
|
|
* have finished.
|
|
*/
|
|
*/
|
|
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
|
|
|
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
|
|
|
|
|
+ ggtt->invalidate(vm->i915);
|
|
}
|
|
}
|
|
|
|
|
|
struct insert_entries {
|
|
struct insert_entries {
|
|
@@ -2475,15 +2475,13 @@ static void gen6_ggtt_insert_page(struct i915_address_space *vm,
|
|
enum i915_cache_level level,
|
|
enum i915_cache_level level,
|
|
u32 flags)
|
|
u32 flags)
|
|
{
|
|
{
|
|
- struct drm_i915_private *dev_priv = vm->i915;
|
|
|
|
|
|
+ struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
|
gen6_pte_t __iomem *pte =
|
|
gen6_pte_t __iomem *pte =
|
|
- (gen6_pte_t __iomem *)dev_priv->ggtt.gsm +
|
|
|
|
- (offset >> PAGE_SHIFT);
|
|
|
|
|
|
+ (gen6_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT);
|
|
|
|
|
|
iowrite32(vm->pte_encode(addr, level, flags), pte);
|
|
iowrite32(vm->pte_encode(addr, level, flags), pte);
|
|
|
|
|
|
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
|
|
|
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
|
|
|
|
|
+ ggtt->invalidate(vm->i915);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2497,7 +2495,6 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
|
|
uint64_t start,
|
|
uint64_t start,
|
|
enum i915_cache_level level, u32 flags)
|
|
enum i915_cache_level level, u32 flags)
|
|
{
|
|
{
|
|
- struct drm_i915_private *dev_priv = vm->i915;
|
|
|
|
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
|
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
|
struct sgt_iter sgt_iter;
|
|
struct sgt_iter sgt_iter;
|
|
gen6_pte_t __iomem *gtt_entries;
|
|
gen6_pte_t __iomem *gtt_entries;
|
|
@@ -2525,8 +2522,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
|
|
* want to flush the TLBs only after we're certain all the PTE updates
|
|
* want to flush the TLBs only after we're certain all the PTE updates
|
|
* have finished.
|
|
* have finished.
|
|
*/
|
|
*/
|
|
- I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
|
|
|
|
- POSTING_READ(GFX_FLSH_CNTL_GEN6);
|
|
|
|
|
|
+ ggtt->invalidate(vm->i915);
|
|
}
|
|
}
|
|
|
|
|
|
static void nop_clear_range(struct i915_address_space *vm,
|
|
static void nop_clear_range(struct i915_address_space *vm,
|
|
@@ -2723,11 +2719,11 @@ static void i915_gtt_color_adjust(const struct drm_mm_node *node,
|
|
u64 *end)
|
|
u64 *end)
|
|
{
|
|
{
|
|
if (node->color != color)
|
|
if (node->color != color)
|
|
- *start += 4096;
|
|
|
|
|
|
+ *start += I915_GTT_PAGE_SIZE;
|
|
|
|
|
|
node = list_next_entry(node, node_list);
|
|
node = list_next_entry(node, node_list);
|
|
if (node->allocated && node->color != color)
|
|
if (node->allocated && node->color != color)
|
|
- *end -= 4096;
|
|
|
|
|
|
+ *end -= I915_GTT_PAGE_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
|
|
int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
|
|
@@ -2754,7 +2750,7 @@ int i915_gem_init_ggtt(struct drm_i915_private *dev_priv)
|
|
/* Reserve a mappable slot for our lockless error capture */
|
|
/* Reserve a mappable slot for our lockless error capture */
|
|
ret = drm_mm_insert_node_in_range_generic(&ggtt->base.mm,
|
|
ret = drm_mm_insert_node_in_range_generic(&ggtt->base.mm,
|
|
&ggtt->error_capture,
|
|
&ggtt->error_capture,
|
|
- 4096, 0,
|
|
|
|
|
|
+ PAGE_SIZE, 0,
|
|
I915_COLOR_UNEVICTABLE,
|
|
I915_COLOR_UNEVICTABLE,
|
|
0, ggtt->mappable_end,
|
|
0, ggtt->mappable_end,
|
|
0, 0);
|
|
0, 0);
|
|
@@ -3086,6 +3082,8 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
|
|
if (IS_CHERRYVIEW(dev_priv))
|
|
if (IS_CHERRYVIEW(dev_priv))
|
|
ggtt->base.insert_entries = gen8_ggtt_insert_entries__BKL;
|
|
ggtt->base.insert_entries = gen8_ggtt_insert_entries__BKL;
|
|
|
|
|
|
|
|
+ ggtt->invalidate = gen6_ggtt_invalidate;
|
|
|
|
+
|
|
return ggtt_probe_common(ggtt, size);
|
|
return ggtt_probe_common(ggtt, size);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3123,6 +3121,8 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
|
|
ggtt->base.unbind_vma = ggtt_unbind_vma;
|
|
ggtt->base.unbind_vma = ggtt_unbind_vma;
|
|
ggtt->base.cleanup = gen6_gmch_remove;
|
|
ggtt->base.cleanup = gen6_gmch_remove;
|
|
|
|
|
|
|
|
+ ggtt->invalidate = gen6_ggtt_invalidate;
|
|
|
|
+
|
|
if (HAS_EDRAM(dev_priv))
|
|
if (HAS_EDRAM(dev_priv))
|
|
ggtt->base.pte_encode = iris_pte_encode;
|
|
ggtt->base.pte_encode = iris_pte_encode;
|
|
else if (IS_HASWELL(dev_priv))
|
|
else if (IS_HASWELL(dev_priv))
|
|
@@ -3166,6 +3166,8 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt)
|
|
ggtt->base.unbind_vma = ggtt_unbind_vma;
|
|
ggtt->base.unbind_vma = ggtt_unbind_vma;
|
|
ggtt->base.cleanup = i915_gmch_remove;
|
|
ggtt->base.cleanup = i915_gmch_remove;
|
|
|
|
|
|
|
|
+ ggtt->invalidate = gmch_ggtt_invalidate;
|
|
|
|
+
|
|
if (unlikely(ggtt->do_idle_maps))
|
|
if (unlikely(ggtt->do_idle_maps))
|
|
DRM_INFO("applying Ironlake quirks for intel_iommu\n");
|
|
DRM_INFO("applying Ironlake quirks for intel_iommu\n");
|
|
|
|
|
|
@@ -3284,6 +3286,16 @@ int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void i915_ggtt_enable_guc(struct drm_i915_private *i915)
|
|
|
|
+{
|
|
|
|
+ i915->ggtt.invalidate = guc_ggtt_invalidate;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void i915_ggtt_disable_guc(struct drm_i915_private *i915)
|
|
|
|
+{
|
|
|
|
+ i915->ggtt.invalidate = gen6_ggtt_invalidate;
|
|
|
|
+}
|
|
|
|
+
|
|
void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
|
|
void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
|
|
{
|
|
{
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
|
@@ -3347,52 +3359,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- i915_ggtt_flush(dev_priv);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-struct i915_vma *
|
|
|
|
-i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
|
|
|
|
- struct i915_address_space *vm,
|
|
|
|
- const struct i915_ggtt_view *view)
|
|
|
|
-{
|
|
|
|
- struct rb_node *rb;
|
|
|
|
-
|
|
|
|
- rb = obj->vma_tree.rb_node;
|
|
|
|
- while (rb) {
|
|
|
|
- struct i915_vma *vma = rb_entry(rb, struct i915_vma, obj_node);
|
|
|
|
- long cmp;
|
|
|
|
-
|
|
|
|
- cmp = i915_vma_compare(vma, vm, view);
|
|
|
|
- if (cmp == 0)
|
|
|
|
- return vma;
|
|
|
|
-
|
|
|
|
- if (cmp < 0)
|
|
|
|
- rb = rb->rb_right;
|
|
|
|
- else
|
|
|
|
- rb = rb->rb_left;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-struct i915_vma *
|
|
|
|
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
|
|
|
|
- struct i915_address_space *vm,
|
|
|
|
- const struct i915_ggtt_view *view)
|
|
|
|
-{
|
|
|
|
- struct i915_vma *vma;
|
|
|
|
-
|
|
|
|
- lockdep_assert_held(&obj->base.dev->struct_mutex);
|
|
|
|
- GEM_BUG_ON(view && !i915_is_ggtt(vm));
|
|
|
|
-
|
|
|
|
- vma = i915_gem_obj_to_vma(obj, vm, view);
|
|
|
|
- if (!vma) {
|
|
|
|
- vma = i915_vma_create(obj, vm, view);
|
|
|
|
- GEM_BUG_ON(vma != i915_gem_obj_to_vma(obj, vm, view));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- GEM_BUG_ON(i915_vma_is_closed(vma));
|
|
|
|
- return vma;
|
|
|
|
|
|
+ i915_ggtt_invalidate(dev_priv);
|
|
}
|
|
}
|
|
|
|
|
|
static struct scatterlist *
|
|
static struct scatterlist *
|
|
@@ -3492,7 +3459,7 @@ intel_partial_pages(const struct i915_ggtt_view *view,
|
|
{
|
|
{
|
|
struct sg_table *st;
|
|
struct sg_table *st;
|
|
struct scatterlist *sg, *iter;
|
|
struct scatterlist *sg, *iter;
|
|
- unsigned int count = view->params.partial.size;
|
|
|
|
|
|
+ unsigned int count = view->partial.size;
|
|
unsigned int offset;
|
|
unsigned int offset;
|
|
int ret = -ENOMEM;
|
|
int ret = -ENOMEM;
|
|
|
|
|
|
@@ -3504,9 +3471,7 @@ intel_partial_pages(const struct i915_ggtt_view *view,
|
|
if (ret)
|
|
if (ret)
|
|
goto err_sg_alloc;
|
|
goto err_sg_alloc;
|
|
|
|
|
|
- iter = i915_gem_object_get_sg(obj,
|
|
|
|
- view->params.partial.offset,
|
|
|
|
- &offset);
|
|
|
|
|
|
+ iter = i915_gem_object_get_sg(obj, view->partial.offset, &offset);
|
|
GEM_BUG_ON(!iter);
|
|
GEM_BUG_ON(!iter);
|
|
|
|
|
|
sg = st->sgl;
|
|
sg = st->sgl;
|
|
@@ -3558,7 +3523,8 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
|
|
vma->pages = vma->obj->mm.pages;
|
|
vma->pages = vma->obj->mm.pages;
|
|
else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
|
|
else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED)
|
|
vma->pages =
|
|
vma->pages =
|
|
- intel_rotate_fb_obj_pages(&vma->ggtt_view.params.rotated, vma->obj);
|
|
|
|
|
|
+ intel_rotate_fb_obj_pages(&vma->ggtt_view.rotated,
|
|
|
|
+ vma->obj);
|
|
else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
|
|
else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL)
|
|
vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj);
|
|
vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj);
|
|
else
|
|
else
|
|
@@ -3579,3 +3545,207 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * i915_gem_gtt_reserve - reserve a node in an address_space (GTT)
|
|
|
|
+ * @vm: the &struct i915_address_space
|
|
|
|
+ * @node: the &struct drm_mm_node (typically i915_vma.mode)
|
|
|
|
+ * @size: how much space to allocate inside the GTT,
|
|
|
|
+ * must be #I915_GTT_PAGE_SIZE aligned
|
|
|
|
+ * @offset: where to insert inside the GTT,
|
|
|
|
+ * must be #I915_GTT_MIN_ALIGNMENT aligned, and the node
|
|
|
|
+ * (@offset + @size) must fit within the address space
|
|
|
|
+ * @color: color to apply to node, if this node is not from a VMA,
|
|
|
|
+ * color must be #I915_COLOR_UNEVICTABLE
|
|
|
|
+ * @flags: control search and eviction behaviour
|
|
|
|
+ *
|
|
|
|
+ * i915_gem_gtt_reserve() tries to insert the @node at the exact @offset inside
|
|
|
|
+ * the address space (using @size and @color). If the @node does not fit, it
|
|
|
|
+ * tries to evict any overlapping nodes from the GTT, including any
|
|
|
|
+ * neighbouring nodes if the colors do not match (to ensure guard pages between
|
|
|
|
+ * differing domains). See i915_gem_evict_for_node() for the gory details
|
|
|
|
+ * on the eviction algorithm. #PIN_NONBLOCK may used to prevent waiting on
|
|
|
|
+ * evicting active overlapping objects, and any overlapping node that is pinned
|
|
|
|
+ * or marked as unevictable will also result in failure.
|
|
|
|
+ *
|
|
|
|
+ * Returns: 0 on success, -ENOSPC if no suitable hole is found, -EINTR if
|
|
|
|
+ * asked to wait for eviction and interrupted.
|
|
|
|
+ */
|
|
|
|
+int i915_gem_gtt_reserve(struct i915_address_space *vm,
|
|
|
|
+ struct drm_mm_node *node,
|
|
|
|
+ u64 size, u64 offset, unsigned long color,
|
|
|
|
+ unsigned int flags)
|
|
|
|
+{
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ GEM_BUG_ON(!size);
|
|
|
|
+ GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
|
|
|
|
+ GEM_BUG_ON(!IS_ALIGNED(offset, I915_GTT_MIN_ALIGNMENT));
|
|
|
|
+ GEM_BUG_ON(range_overflows(offset, size, vm->total));
|
|
|
|
+ GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base);
|
|
|
|
+ GEM_BUG_ON(drm_mm_node_allocated(node));
|
|
|
|
+
|
|
|
|
+ node->size = size;
|
|
|
|
+ node->start = offset;
|
|
|
|
+ node->color = color;
|
|
|
|
+
|
|
|
|
+ err = drm_mm_reserve_node(&vm->mm, node);
|
|
|
|
+ if (err != -ENOSPC)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ err = i915_gem_evict_for_node(vm, node, flags);
|
|
|
|
+ if (err == 0)
|
|
|
|
+ err = drm_mm_reserve_node(&vm->mm, node);
|
|
|
|
+
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u64 random_offset(u64 start, u64 end, u64 len, u64 align)
|
|
|
|
+{
|
|
|
|
+ u64 range, addr;
|
|
|
|
+
|
|
|
|
+ GEM_BUG_ON(range_overflows(start, len, end));
|
|
|
|
+ GEM_BUG_ON(round_up(start, align) > round_down(end - len, align));
|
|
|
|
+
|
|
|
|
+ range = round_down(end - len, align) - round_up(start, align);
|
|
|
|
+ if (range) {
|
|
|
|
+ if (sizeof(unsigned long) == sizeof(u64)) {
|
|
|
|
+ addr = get_random_long();
|
|
|
|
+ } else {
|
|
|
|
+ addr = get_random_int();
|
|
|
|
+ if (range > U32_MAX) {
|
|
|
|
+ addr <<= 32;
|
|
|
|
+ addr |= get_random_int();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ div64_u64_rem(addr, range, &addr);
|
|
|
|
+ start += addr;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return round_up(start, align);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * i915_gem_gtt_insert - insert a node into an address_space (GTT)
|
|
|
|
+ * @vm: the &struct i915_address_space
|
|
|
|
+ * @node: the &struct drm_mm_node (typically i915_vma.node)
|
|
|
|
+ * @size: how much space to allocate inside the GTT,
|
|
|
|
+ * must be #I915_GTT_PAGE_SIZE aligned
|
|
|
|
+ * @alignment: required alignment of starting offset, may be 0 but
|
|
|
|
+ * if specified, this must be a power-of-two and at least
|
|
|
|
+ * #I915_GTT_MIN_ALIGNMENT
|
|
|
|
+ * @color: color to apply to node
|
|
|
|
+ * @start: start of any range restriction inside GTT (0 for all),
|
|
|
|
+ * must be #I915_GTT_PAGE_SIZE aligned
|
|
|
|
+ * @end: end of any range restriction inside GTT (U64_MAX for all),
|
|
|
|
+ * must be #I915_GTT_PAGE_SIZE aligned if not U64_MAX
|
|
|
|
+ * @flags: control search and eviction behaviour
|
|
|
|
+ *
|
|
|
|
+ * i915_gem_gtt_insert() first searches for an available hole into which
|
|
|
|
+ * is can insert the node. The hole address is aligned to @alignment and
|
|
|
|
+ * its @size must then fit entirely within the [@start, @end] bounds. The
|
|
|
|
+ * nodes on either side of the hole must match @color, or else a guard page
|
|
|
|
+ * will be inserted between the two nodes (or the node evicted). If no
|
|
|
|
+ * suitable hole is found, first a victim is randomly selected and tested
|
|
|
|
+ * for eviction, otherwise then the LRU list of objects within the GTT
|
|
|
|
+ * is scanned to find the first set of replacement nodes to create the hole.
|
|
|
|
+ * Those old overlapping nodes are evicted from the GTT (and so must be
|
|
|
|
+ * rebound before any future use). Any node that is currently pinned cannot
|
|
|
|
+ * be evicted (see i915_vma_pin()). Similar if the node's VMA is currently
|
|
|
|
+ * active and #PIN_NONBLOCK is specified, that node is also skipped when
|
|
|
|
+ * searching for an eviction candidate. See i915_gem_evict_something() for
|
|
|
|
+ * the gory details on the eviction algorithm.
|
|
|
|
+ *
|
|
|
|
+ * Returns: 0 on success, -ENOSPC if no suitable hole is found, -EINTR if
|
|
|
|
+ * asked to wait for eviction and interrupted.
|
|
|
|
+ */
|
|
|
|
+int i915_gem_gtt_insert(struct i915_address_space *vm,
|
|
|
|
+ struct drm_mm_node *node,
|
|
|
|
+ u64 size, u64 alignment, unsigned long color,
|
|
|
|
+ u64 start, u64 end, unsigned int flags)
|
|
|
|
+{
|
|
|
|
+ u32 search_flag, alloc_flag;
|
|
|
|
+ u64 offset;
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ lockdep_assert_held(&vm->i915->drm.struct_mutex);
|
|
|
|
+ GEM_BUG_ON(!size);
|
|
|
|
+ GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
|
|
|
|
+ GEM_BUG_ON(alignment && !is_power_of_2(alignment));
|
|
|
|
+ GEM_BUG_ON(alignment && !IS_ALIGNED(alignment, I915_GTT_MIN_ALIGNMENT));
|
|
|
|
+ GEM_BUG_ON(start >= end);
|
|
|
|
+ GEM_BUG_ON(start > 0 && !IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
|
|
|
|
+ GEM_BUG_ON(end < U64_MAX && !IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
|
|
|
|
+ GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->base);
|
|
|
|
+ GEM_BUG_ON(drm_mm_node_allocated(node));
|
|
|
|
+
|
|
|
|
+ if (unlikely(range_overflows(start, size, end)))
|
|
|
|
+ return -ENOSPC;
|
|
|
|
+
|
|
|
|
+ if (unlikely(round_up(start, alignment) > round_down(end - size, alignment)))
|
|
|
|
+ return -ENOSPC;
|
|
|
|
+
|
|
|
|
+ if (flags & PIN_HIGH) {
|
|
|
|
+ search_flag = DRM_MM_SEARCH_BELOW;
|
|
|
|
+ alloc_flag = DRM_MM_CREATE_TOP;
|
|
|
|
+ } else {
|
|
|
|
+ search_flag = DRM_MM_SEARCH_DEFAULT;
|
|
|
|
+ alloc_flag = DRM_MM_CREATE_DEFAULT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* We only allocate in PAGE_SIZE/GTT_PAGE_SIZE (4096) chunks,
|
|
|
|
+ * so we know that we always have a minimum alignment of 4096.
|
|
|
|
+ * The drm_mm range manager is optimised to return results
|
|
|
|
+ * with zero alignment, so where possible use the optimal
|
|
|
|
+ * path.
|
|
|
|
+ */
|
|
|
|
+ BUILD_BUG_ON(I915_GTT_MIN_ALIGNMENT > I915_GTT_PAGE_SIZE);
|
|
|
|
+ if (alignment <= I915_GTT_MIN_ALIGNMENT)
|
|
|
|
+ alignment = 0;
|
|
|
|
+
|
|
|
|
+ err = drm_mm_insert_node_in_range_generic(&vm->mm, node,
|
|
|
|
+ size, alignment, color,
|
|
|
|
+ start, end,
|
|
|
|
+ search_flag, alloc_flag);
|
|
|
|
+ if (err != -ENOSPC)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ /* No free space, pick a slot at random.
|
|
|
|
+ *
|
|
|
|
+ * There is a pathological case here using a GTT shared between
|
|
|
|
+ * mmap and GPU (i.e. ggtt/aliasing_ppgtt but not full-ppgtt):
|
|
|
|
+ *
|
|
|
|
+ * |<-- 256 MiB aperture -->||<-- 1792 MiB unmappable -->|
|
|
|
|
+ * (64k objects) (448k objects)
|
|
|
|
+ *
|
|
|
|
+ * Now imagine that the eviction LRU is ordered top-down (just because
|
|
|
|
+ * pathology meets real life), and that we need to evict an object to
|
|
|
|
+ * make room inside the aperture. The eviction scan then has to walk
|
|
|
|
+ * the 448k list before it finds one within range. And now imagine that
|
|
|
|
+ * it has to search for a new hole between every byte inside the memcpy,
|
|
|
|
+ * for several simultaneous clients.
|
|
|
|
+ *
|
|
|
|
+ * On a full-ppgtt system, if we have run out of available space, there
|
|
|
|
+ * will be lots and lots of objects in the eviction list! Again,
|
|
|
|
+ * searching that LRU list may be slow if we are also applying any
|
|
|
|
+ * range restrictions (e.g. restriction to low 4GiB) and so, for
|
|
|
|
+ * simplicity and similarilty between different GTT, try the single
|
|
|
|
+ * random replacement first.
|
|
|
|
+ */
|
|
|
|
+ offset = random_offset(start, end,
|
|
|
|
+ size, alignment ?: I915_GTT_MIN_ALIGNMENT);
|
|
|
|
+ err = i915_gem_gtt_reserve(vm, node, size, offset, color, flags);
|
|
|
|
+ if (err != -ENOSPC)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ /* Randomly selected placement is pinned, do a search */
|
|
|
|
+ err = i915_gem_evict_something(vm, size, alignment, color,
|
|
|
|
+ start, end, flags);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
|
|
+ search_flag = DRM_MM_SEARCH_DEFAULT;
|
|
|
|
+ return drm_mm_insert_node_in_range_generic(&vm->mm, node,
|
|
|
|
+ size, alignment, color,
|
|
|
|
+ start, end,
|
|
|
|
+ search_flag, alloc_flag);
|
|
|
|
+}
|