162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2020 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/log2.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "gem/i915_gem_internal.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "gen6_ppgtt.h" 1162306a36Sopenharmony_ci#include "i915_scatterlist.h" 1262306a36Sopenharmony_ci#include "i915_trace.h" 1362306a36Sopenharmony_ci#include "i915_vgpu.h" 1462306a36Sopenharmony_ci#include "intel_gt_regs.h" 1562306a36Sopenharmony_ci#include "intel_engine_regs.h" 1662306a36Sopenharmony_ci#include "intel_gt.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* Write pde (index) from the page directory @pd to the page table @pt */ 1962306a36Sopenharmony_cistatic void gen6_write_pde(const struct gen6_ppgtt *ppgtt, 2062306a36Sopenharmony_ci const unsigned int pde, 2162306a36Sopenharmony_ci const struct i915_page_table *pt) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci dma_addr_t addr = pt ? px_dma(pt) : px_dma(ppgtt->base.vm.scratch[1]); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* Caller needs to make sure the write completes if necessary */ 2662306a36Sopenharmony_ci iowrite32(GEN6_PDE_ADDR_ENCODE(addr) | GEN6_PDE_VALID, 2762306a36Sopenharmony_ci ppgtt->pd_addr + pde); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_civoid gen7_ppgtt_enable(struct intel_gt *gt) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct drm_i915_private *i915 = gt->i915; 3362306a36Sopenharmony_ci struct intel_uncore *uncore = gt->uncore; 3462306a36Sopenharmony_ci u32 ecochk; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci intel_uncore_rmw(uncore, GAC_ECO_BITS, 0, ECOBITS_PPGTT_CACHE64B); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci ecochk = intel_uncore_read(uncore, GAM_ECOCHK); 3962306a36Sopenharmony_ci if (IS_HASWELL(i915)) { 4062306a36Sopenharmony_ci ecochk |= ECOCHK_PPGTT_WB_HSW; 4162306a36Sopenharmony_ci } else { 4262306a36Sopenharmony_ci ecochk |= ECOCHK_PPGTT_LLC_IVB; 4362306a36Sopenharmony_ci ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci intel_uncore_write(uncore, GAM_ECOCHK, ecochk); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_civoid gen6_ppgtt_enable(struct intel_gt *gt) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct intel_uncore *uncore = gt->uncore; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci intel_uncore_rmw(uncore, 5362306a36Sopenharmony_ci GAC_ECO_BITS, 5462306a36Sopenharmony_ci 0, 5562306a36Sopenharmony_ci ECOBITS_SNB_BIT | ECOBITS_PPGTT_CACHE64B); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci intel_uncore_rmw(uncore, 5862306a36Sopenharmony_ci GAB_CTL, 5962306a36Sopenharmony_ci 0, 6062306a36Sopenharmony_ci GAB_CTL_CONT_AFTER_PAGEFAULT); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci intel_uncore_rmw(uncore, 6362306a36Sopenharmony_ci GAM_ECOCHK, 6462306a36Sopenharmony_ci 0, 6562306a36Sopenharmony_ci ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (HAS_PPGTT(uncore->i915)) /* may be disabled for VT-d */ 6862306a36Sopenharmony_ci intel_uncore_write(uncore, 6962306a36Sopenharmony_ci GFX_MODE, 7062306a36Sopenharmony_ci _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* PPGTT support for Sandybdrige/Gen6 and later */ 7462306a36Sopenharmony_cistatic void gen6_ppgtt_clear_range(struct i915_address_space *vm, 7562306a36Sopenharmony_ci u64 start, u64 length) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct gen6_ppgtt * const ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); 7862306a36Sopenharmony_ci const unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 7962306a36Sopenharmony_ci const gen6_pte_t scratch_pte = vm->scratch[0]->encode; 8062306a36Sopenharmony_ci unsigned int pde = first_entry / GEN6_PTES; 8162306a36Sopenharmony_ci unsigned int pte = first_entry % GEN6_PTES; 8262306a36Sopenharmony_ci unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci while (num_entries) { 8562306a36Sopenharmony_ci struct i915_page_table * const pt = 8662306a36Sopenharmony_ci i915_pt_entry(ppgtt->base.pd, pde++); 8762306a36Sopenharmony_ci const unsigned int count = min(num_entries, GEN6_PTES - pte); 8862306a36Sopenharmony_ci gen6_pte_t *vaddr; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci num_entries -= count; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci GEM_BUG_ON(count > atomic_read(&pt->used)); 9362306a36Sopenharmony_ci if (!atomic_sub_return(count, &pt->used)) 9462306a36Sopenharmony_ci ppgtt->scan_for_unused_pt = true; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * Note that the hw doesn't support removing PDE on the fly 9862306a36Sopenharmony_ci * (they are cached inside the context with no means to 9962306a36Sopenharmony_ci * invalidate the cache), so we can only reset the PTE 10062306a36Sopenharmony_ci * entries back to scratch. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci vaddr = px_vaddr(pt); 10462306a36Sopenharmony_ci memset32(vaddr + pte, scratch_pte, count); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci pte = 0; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void gen6_ppgtt_insert_entries(struct i915_address_space *vm, 11162306a36Sopenharmony_ci struct i915_vma_resource *vma_res, 11262306a36Sopenharmony_ci unsigned int pat_index, 11362306a36Sopenharmony_ci u32 flags) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); 11662306a36Sopenharmony_ci struct i915_page_directory * const pd = ppgtt->pd; 11762306a36Sopenharmony_ci unsigned int first_entry = vma_res->start / I915_GTT_PAGE_SIZE; 11862306a36Sopenharmony_ci unsigned int act_pt = first_entry / GEN6_PTES; 11962306a36Sopenharmony_ci unsigned int act_pte = first_entry % GEN6_PTES; 12062306a36Sopenharmony_ci const u32 pte_encode = vm->pte_encode(0, pat_index, flags); 12162306a36Sopenharmony_ci struct sgt_dma iter = sgt_dma(vma_res); 12262306a36Sopenharmony_ci gen6_pte_t *vaddr; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci GEM_BUG_ON(!pd->entry[act_pt]); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci vaddr = px_vaddr(i915_pt_entry(pd, act_pt)); 12762306a36Sopenharmony_ci do { 12862306a36Sopenharmony_ci GEM_BUG_ON(sg_dma_len(iter.sg) < I915_GTT_PAGE_SIZE); 12962306a36Sopenharmony_ci vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci iter.dma += I915_GTT_PAGE_SIZE; 13262306a36Sopenharmony_ci if (iter.dma == iter.max) { 13362306a36Sopenharmony_ci iter.sg = __sg_next(iter.sg); 13462306a36Sopenharmony_ci if (!iter.sg || sg_dma_len(iter.sg) == 0) 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci iter.dma = sg_dma_address(iter.sg); 13862306a36Sopenharmony_ci iter.max = iter.dma + sg_dma_len(iter.sg); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (++act_pte == GEN6_PTES) { 14262306a36Sopenharmony_ci vaddr = px_vaddr(i915_pt_entry(pd, ++act_pt)); 14362306a36Sopenharmony_ci act_pte = 0; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci } while (1); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void gen6_flush_pd(struct gen6_ppgtt *ppgtt, u64 start, u64 end) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct i915_page_directory * const pd = ppgtt->base.pd; 15362306a36Sopenharmony_ci struct i915_page_table *pt; 15462306a36Sopenharmony_ci unsigned int pde; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci start = round_down(start, SZ_64K); 15762306a36Sopenharmony_ci end = round_up(end, SZ_64K) - start; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci mutex_lock(&ppgtt->flush); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci gen6_for_each_pde(pt, pd, start, end, pde) 16262306a36Sopenharmony_ci gen6_write_pde(ppgtt, pde, pt); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci mb(); 16562306a36Sopenharmony_ci ioread32(ppgtt->pd_addr + pde - 1); 16662306a36Sopenharmony_ci gen6_ggtt_invalidate(ppgtt->base.vm.gt->ggtt); 16762306a36Sopenharmony_ci mb(); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci mutex_unlock(&ppgtt->flush); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void gen6_alloc_va_range(struct i915_address_space *vm, 17362306a36Sopenharmony_ci struct i915_vm_pt_stash *stash, 17462306a36Sopenharmony_ci u64 start, u64 length) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); 17762306a36Sopenharmony_ci struct i915_page_directory * const pd = ppgtt->base.pd; 17862306a36Sopenharmony_ci struct i915_page_table *pt; 17962306a36Sopenharmony_ci bool flush = false; 18062306a36Sopenharmony_ci u64 from = start; 18162306a36Sopenharmony_ci unsigned int pde; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci spin_lock(&pd->lock); 18462306a36Sopenharmony_ci gen6_for_each_pde(pt, pd, start, length, pde) { 18562306a36Sopenharmony_ci const unsigned int count = gen6_pte_count(start, length); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (!pt) { 18862306a36Sopenharmony_ci spin_unlock(&pd->lock); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci pt = stash->pt[0]; 19162306a36Sopenharmony_ci __i915_gem_object_pin_pages(pt->base); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci fill32_px(pt, vm->scratch[0]->encode); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci spin_lock(&pd->lock); 19662306a36Sopenharmony_ci if (!pd->entry[pde]) { 19762306a36Sopenharmony_ci stash->pt[0] = pt->stash; 19862306a36Sopenharmony_ci atomic_set(&pt->used, 0); 19962306a36Sopenharmony_ci pd->entry[pde] = pt; 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci pt = pd->entry[pde]; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci flush = true; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci atomic_add(count, &pt->used); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci spin_unlock(&pd->lock); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (flush && i915_vma_is_bound(ppgtt->vma, I915_VMA_GLOBAL_BIND)) { 21262306a36Sopenharmony_ci intel_wakeref_t wakeref; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci with_intel_runtime_pm(&vm->i915->runtime_pm, wakeref) 21562306a36Sopenharmony_ci gen6_flush_pd(ppgtt, from, start); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int gen6_ppgtt_init_scratch(struct gen6_ppgtt *ppgtt) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct i915_address_space * const vm = &ppgtt->base.vm; 22262306a36Sopenharmony_ci int ret; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ret = setup_scratch_page(vm); 22562306a36Sopenharmony_ci if (ret) 22662306a36Sopenharmony_ci return ret; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci vm->scratch[0]->encode = 22962306a36Sopenharmony_ci vm->pte_encode(px_dma(vm->scratch[0]), 23062306a36Sopenharmony_ci i915_gem_get_pat_index(vm->i915, 23162306a36Sopenharmony_ci I915_CACHE_NONE), 23262306a36Sopenharmony_ci PTE_READ_ONLY); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci vm->scratch[1] = vm->alloc_pt_dma(vm, I915_GTT_PAGE_SIZE_4K); 23562306a36Sopenharmony_ci if (IS_ERR(vm->scratch[1])) { 23662306a36Sopenharmony_ci ret = PTR_ERR(vm->scratch[1]); 23762306a36Sopenharmony_ci goto err_scratch0; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ret = map_pt_dma(vm, vm->scratch[1]); 24162306a36Sopenharmony_ci if (ret) 24262306a36Sopenharmony_ci goto err_scratch1; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci fill32_px(vm->scratch[1], vm->scratch[0]->encode); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cierr_scratch1: 24962306a36Sopenharmony_ci i915_gem_object_put(vm->scratch[1]); 25062306a36Sopenharmony_cierr_scratch0: 25162306a36Sopenharmony_ci i915_gem_object_put(vm->scratch[0]); 25262306a36Sopenharmony_ci vm->scratch[0] = NULL; 25362306a36Sopenharmony_ci return ret; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void gen6_ppgtt_free_pd(struct gen6_ppgtt *ppgtt) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct i915_page_directory * const pd = ppgtt->base.pd; 25962306a36Sopenharmony_ci struct i915_page_table *pt; 26062306a36Sopenharmony_ci u32 pde; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci gen6_for_all_pdes(pt, pd, pde) 26362306a36Sopenharmony_ci if (pt) 26462306a36Sopenharmony_ci free_pt(&ppgtt->base.vm, pt); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic void gen6_ppgtt_cleanup(struct i915_address_space *vm) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci gen6_ppgtt_free_pd(ppgtt); 27262306a36Sopenharmony_ci free_scratch(vm); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (ppgtt->base.pd) 27562306a36Sopenharmony_ci free_pd(&ppgtt->base.vm, ppgtt->base.pd); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci mutex_destroy(&ppgtt->flush); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void pd_vma_bind(struct i915_address_space *vm, 28162306a36Sopenharmony_ci struct i915_vm_pt_stash *stash, 28262306a36Sopenharmony_ci struct i915_vma_resource *vma_res, 28362306a36Sopenharmony_ci unsigned int pat_index, 28462306a36Sopenharmony_ci u32 unused) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 28762306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt = vma_res->private; 28862306a36Sopenharmony_ci u32 ggtt_offset = vma_res->start / I915_GTT_PAGE_SIZE; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ppgtt->pp_dir = ggtt_offset * sizeof(gen6_pte_t) << 10; 29162306a36Sopenharmony_ci ppgtt->pd_addr = (gen6_pte_t __iomem *)ggtt->gsm + ggtt_offset; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci gen6_flush_pd(ppgtt, 0, ppgtt->base.vm.total); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void pd_vma_unbind(struct i915_address_space *vm, 29762306a36Sopenharmony_ci struct i915_vma_resource *vma_res) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt = vma_res->private; 30062306a36Sopenharmony_ci struct i915_page_directory * const pd = ppgtt->base.pd; 30162306a36Sopenharmony_ci struct i915_page_table *pt; 30262306a36Sopenharmony_ci unsigned int pde; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!ppgtt->scan_for_unused_pt) 30562306a36Sopenharmony_ci return; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Free all no longer used page tables */ 30862306a36Sopenharmony_ci gen6_for_all_pdes(pt, ppgtt->base.pd, pde) { 30962306a36Sopenharmony_ci if (!pt || atomic_read(&pt->used)) 31062306a36Sopenharmony_ci continue; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci free_pt(&ppgtt->base.vm, pt); 31362306a36Sopenharmony_ci pd->entry[pde] = NULL; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ppgtt->scan_for_unused_pt = false; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic const struct i915_vma_ops pd_vma_ops = { 32062306a36Sopenharmony_ci .bind_vma = pd_vma_bind, 32162306a36Sopenharmony_ci .unbind_vma = pd_vma_unbind, 32262306a36Sopenharmony_ci}; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ciint gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base); 32762306a36Sopenharmony_ci int err; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref)); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt 33362306a36Sopenharmony_ci * which will be pinned into every active context. 33462306a36Sopenharmony_ci * (When vma->pin_count becomes atomic, I expect we will naturally 33562306a36Sopenharmony_ci * need a larger, unpacked, type and kill this redundancy.) 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci if (atomic_add_unless(&ppgtt->pin_count, 1, 0)) 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* grab the ppgtt resv to pin the object */ 34162306a36Sopenharmony_ci err = i915_vm_lock_objects(&ppgtt->base.vm, ww); 34262306a36Sopenharmony_ci if (err) 34362306a36Sopenharmony_ci return err; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* 34662306a36Sopenharmony_ci * PPGTT PDEs reside in the GGTT and consists of 512 entries. The 34762306a36Sopenharmony_ci * allocator works in address space sizes, so it's multiplied by page 34862306a36Sopenharmony_ci * size. We allocate at the top of the GTT to avoid fragmentation. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci if (!atomic_read(&ppgtt->pin_count)) { 35162306a36Sopenharmony_ci err = i915_ggtt_pin(ppgtt->vma, ww, GEN6_PD_ALIGN, PIN_HIGH); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci GEM_BUG_ON(ppgtt->vma->fence); 35462306a36Sopenharmony_ci clear_bit(I915_VMA_CAN_FENCE_BIT, __i915_vma_flags(ppgtt->vma)); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci if (!err) 35762306a36Sopenharmony_ci atomic_inc(&ppgtt->pin_count); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return err; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int pd_dummy_obj_get_pages(struct drm_i915_gem_object *obj) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci obj->mm.pages = ZERO_SIZE_PTR; 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic void pd_dummy_obj_put_pages(struct drm_i915_gem_object *obj, 36962306a36Sopenharmony_ci struct sg_table *pages) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic const struct drm_i915_gem_object_ops pd_dummy_obj_ops = { 37462306a36Sopenharmony_ci .name = "pd_dummy_obj", 37562306a36Sopenharmony_ci .get_pages = pd_dummy_obj_get_pages, 37662306a36Sopenharmony_ci .put_pages = pd_dummy_obj_put_pages, 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic struct i915_page_directory * 38062306a36Sopenharmony_cigen6_alloc_top_pd(struct gen6_ppgtt *ppgtt) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct i915_ggtt * const ggtt = ppgtt->base.vm.gt->ggtt; 38362306a36Sopenharmony_ci struct i915_page_directory *pd; 38462306a36Sopenharmony_ci int err; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci pd = __alloc_pd(I915_PDES); 38762306a36Sopenharmony_ci if (unlikely(!pd)) 38862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci pd->pt.base = __i915_gem_object_create_internal(ppgtt->base.vm.gt->i915, 39162306a36Sopenharmony_ci &pd_dummy_obj_ops, 39262306a36Sopenharmony_ci I915_PDES * SZ_4K); 39362306a36Sopenharmony_ci if (IS_ERR(pd->pt.base)) { 39462306a36Sopenharmony_ci err = PTR_ERR(pd->pt.base); 39562306a36Sopenharmony_ci pd->pt.base = NULL; 39662306a36Sopenharmony_ci goto err_pd; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci pd->pt.base->base.resv = i915_vm_resv_get(&ppgtt->base.vm); 40062306a36Sopenharmony_ci pd->pt.base->shares_resv_from = &ppgtt->base.vm; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci ppgtt->vma = i915_vma_instance(pd->pt.base, &ggtt->vm, NULL); 40362306a36Sopenharmony_ci if (IS_ERR(ppgtt->vma)) { 40462306a36Sopenharmony_ci err = PTR_ERR(ppgtt->vma); 40562306a36Sopenharmony_ci ppgtt->vma = NULL; 40662306a36Sopenharmony_ci goto err_pd; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* The dummy object we create is special, override ops.. */ 41062306a36Sopenharmony_ci ppgtt->vma->ops = &pd_vma_ops; 41162306a36Sopenharmony_ci ppgtt->vma->private = ppgtt; 41262306a36Sopenharmony_ci return pd; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cierr_pd: 41562306a36Sopenharmony_ci free_pd(&ppgtt->base.vm, pd); 41662306a36Sopenharmony_ci return ERR_PTR(err); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_civoid gen6_ppgtt_unpin(struct i915_ppgtt *base) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci GEM_BUG_ON(!atomic_read(&ppgtt->pin_count)); 42462306a36Sopenharmony_ci if (atomic_dec_and_test(&ppgtt->pin_count)) 42562306a36Sopenharmony_ci i915_vma_unpin(ppgtt->vma); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistruct i915_ppgtt *gen6_ppgtt_create(struct intel_gt *gt) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct i915_ggtt * const ggtt = gt->ggtt; 43162306a36Sopenharmony_ci struct gen6_ppgtt *ppgtt; 43262306a36Sopenharmony_ci int err; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); 43562306a36Sopenharmony_ci if (!ppgtt) 43662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci mutex_init(&ppgtt->flush); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ppgtt_init(&ppgtt->base, gt, 0); 44162306a36Sopenharmony_ci ppgtt->base.vm.pd_shift = ilog2(SZ_4K * SZ_4K / sizeof(gen6_pte_t)); 44262306a36Sopenharmony_ci ppgtt->base.vm.top = 1; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ppgtt->base.vm.bind_async_flags = I915_VMA_LOCAL_BIND; 44562306a36Sopenharmony_ci ppgtt->base.vm.allocate_va_range = gen6_alloc_va_range; 44662306a36Sopenharmony_ci ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range; 44762306a36Sopenharmony_ci ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries; 44862306a36Sopenharmony_ci ppgtt->base.vm.cleanup = gen6_ppgtt_cleanup; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci ppgtt->base.vm.alloc_pt_dma = alloc_pt_dma; 45162306a36Sopenharmony_ci ppgtt->base.vm.alloc_scratch_dma = alloc_pt_dma; 45262306a36Sopenharmony_ci ppgtt->base.vm.pte_encode = ggtt->vm.pte_encode; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci err = gen6_ppgtt_init_scratch(ppgtt); 45562306a36Sopenharmony_ci if (err) 45662306a36Sopenharmony_ci goto err_put; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ppgtt->base.pd = gen6_alloc_top_pd(ppgtt); 45962306a36Sopenharmony_ci if (IS_ERR(ppgtt->base.pd)) { 46062306a36Sopenharmony_ci err = PTR_ERR(ppgtt->base.pd); 46162306a36Sopenharmony_ci goto err_put; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return &ppgtt->base; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cierr_put: 46762306a36Sopenharmony_ci i915_vm_put(&ppgtt->base.vm); 46862306a36Sopenharmony_ci return ERR_PTR(err); 46962306a36Sopenharmony_ci} 470