12c86e55dSMatthew Auld // SPDX-License-Identifier: MIT 22c86e55dSMatthew Auld /* 32c86e55dSMatthew Auld * Copyright © 2020 Intel Corporation 42c86e55dSMatthew Auld */ 52c86e55dSMatthew Auld 62c86e55dSMatthew Auld #include <asm/set_memory.h> 78801eb48SChen Zhou #include <asm/smp.h> 89ce07d94SLucas De Marchi #include <linux/types.h> 99ce07d94SLucas De Marchi #include <linux/stop_machine.h> 102c86e55dSMatthew Auld 1183d2bdb6SJani Nikula #include <drm/i915_drm.h> 129ce07d94SLucas De Marchi #include <drm/intel-gtt.h> 1383d2bdb6SJani Nikula 14e762bdf5SMatthew Auld #include "gem/i915_gem_lmem.h" 15e762bdf5SMatthew Auld 169ce07d94SLucas De Marchi #include "intel_ggtt_gmch.h" 172c86e55dSMatthew Auld #include "intel_gt.h" 180d6419e9SMatt Roper #include "intel_gt_regs.h" 196bba2b30SPiotr Piórkowski #include "intel_pci_config.h" 202c86e55dSMatthew Auld #include "i915_drv.h" 211bba7323SPiotr Piórkowski #include "i915_pci.h" 222c86e55dSMatthew Auld #include "i915_scatterlist.h" 23a7f46d5bSTvrtko Ursulin #include "i915_utils.h" 242c86e55dSMatthew Auld #include "i915_vgpu.h" 252c86e55dSMatthew Auld 262c86e55dSMatthew Auld #include "intel_gtt.h" 2733e7a975SVille Syrjälä #include "gen8_ppgtt.h" 282c86e55dSMatthew Auld 292ef6efa7SThomas Hellström static inline bool suspend_retains_ptes(struct i915_address_space *vm) 302ef6efa7SThomas Hellström { 312ef6efa7SThomas Hellström return GRAPHICS_VER(vm->i915) >= 8 && 322ef6efa7SThomas Hellström !HAS_LMEM(vm->i915) && 332ef6efa7SThomas Hellström vm->is_ggtt; 342ef6efa7SThomas Hellström } 352ef6efa7SThomas Hellström 362c86e55dSMatthew Auld static void i915_ggtt_color_adjust(const struct drm_mm_node *node, 372c86e55dSMatthew Auld unsigned long color, 382c86e55dSMatthew Auld u64 *start, 392c86e55dSMatthew Auld u64 *end) 402c86e55dSMatthew Auld { 412c86e55dSMatthew Auld if (i915_node_color_differs(node, color)) 422c86e55dSMatthew Auld *start += I915_GTT_PAGE_SIZE; 432c86e55dSMatthew Auld 442c86e55dSMatthew Auld /* 452c86e55dSMatthew Auld * Also leave a space between the unallocated reserved node after the 462c86e55dSMatthew Auld * GTT and any objects within the GTT, i.e. we use the color adjustment 472c86e55dSMatthew Auld * to insert a guard page to prevent prefetches crossing over the 482c86e55dSMatthew Auld * GTT boundary. 492c86e55dSMatthew Auld */ 502c86e55dSMatthew Auld node = list_next_entry(node, node_list); 512c86e55dSMatthew Auld if (node->color != color) 522c86e55dSMatthew Auld *end -= I915_GTT_PAGE_SIZE; 532c86e55dSMatthew Auld } 542c86e55dSMatthew Auld 552c86e55dSMatthew Auld static int ggtt_init_hw(struct i915_ggtt *ggtt) 562c86e55dSMatthew Auld { 572c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 582c86e55dSMatthew Auld 592c86e55dSMatthew Auld i915_address_space_init(&ggtt->vm, VM_CLASS_GGTT); 602c86e55dSMatthew Auld 612c86e55dSMatthew Auld ggtt->vm.is_ggtt = true; 622c86e55dSMatthew Auld 632c86e55dSMatthew Auld /* Only VLV supports read-only GGTT mappings */ 642c86e55dSMatthew Auld ggtt->vm.has_read_only = IS_VALLEYVIEW(i915); 652c86e55dSMatthew Auld 662c86e55dSMatthew Auld if (!HAS_LLC(i915) && !HAS_PPGTT(i915)) 672c86e55dSMatthew Auld ggtt->vm.mm.color_adjust = i915_ggtt_color_adjust; 682c86e55dSMatthew Auld 692c86e55dSMatthew Auld if (ggtt->mappable_end) { 702c86e55dSMatthew Auld if (!io_mapping_init_wc(&ggtt->iomap, 712c86e55dSMatthew Auld ggtt->gmadr.start, 722c86e55dSMatthew Auld ggtt->mappable_end)) { 732c86e55dSMatthew Auld ggtt->vm.cleanup(&ggtt->vm); 742c86e55dSMatthew Auld return -EIO; 752c86e55dSMatthew Auld } 762c86e55dSMatthew Auld 772c86e55dSMatthew Auld ggtt->mtrr = arch_phys_wc_add(ggtt->gmadr.start, 782c86e55dSMatthew Auld ggtt->mappable_end); 792c86e55dSMatthew Auld } 802c86e55dSMatthew Auld 81f899f786SChris Wilson intel_ggtt_init_fences(ggtt); 822c86e55dSMatthew Auld 832c86e55dSMatthew Auld return 0; 842c86e55dSMatthew Auld } 852c86e55dSMatthew Auld 862c86e55dSMatthew Auld /** 872c86e55dSMatthew Auld * i915_ggtt_init_hw - Initialize GGTT hardware 882c86e55dSMatthew Auld * @i915: i915 device 892c86e55dSMatthew Auld */ 902c86e55dSMatthew Auld int i915_ggtt_init_hw(struct drm_i915_private *i915) 912c86e55dSMatthew Auld { 922c86e55dSMatthew Auld int ret; 932c86e55dSMatthew Auld 942c86e55dSMatthew Auld /* 952c86e55dSMatthew Auld * Note that we use page colouring to enforce a guard page at the 962c86e55dSMatthew Auld * end of the address space. This is required as the CS may prefetch 972c86e55dSMatthew Auld * beyond the end of the batch buffer, across the page boundary, 982c86e55dSMatthew Auld * and beyond the end of the GTT if we do not provide a guard. 992c86e55dSMatthew Auld */ 100848915c3SMichał Winiarski ret = ggtt_init_hw(to_gt(i915)->ggtt); 1012c86e55dSMatthew Auld if (ret) 1022c86e55dSMatthew Auld return ret; 1032c86e55dSMatthew Auld 1042c86e55dSMatthew Auld return 0; 1052c86e55dSMatthew Auld } 1062c86e55dSMatthew Auld 1072ef6efa7SThomas Hellström /* 1082ef6efa7SThomas Hellström * Return the value of the last GGTT pte cast to an u64, if 1092ef6efa7SThomas Hellström * the system is supposed to retain ptes across resume. 0 otherwise. 1102ef6efa7SThomas Hellström */ 1112ef6efa7SThomas Hellström static u64 read_last_pte(struct i915_address_space *vm) 1122ef6efa7SThomas Hellström { 1132ef6efa7SThomas Hellström struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 1142ef6efa7SThomas Hellström gen8_pte_t __iomem *ptep; 1152ef6efa7SThomas Hellström 1162ef6efa7SThomas Hellström if (!suspend_retains_ptes(vm)) 1172ef6efa7SThomas Hellström return 0; 1182ef6efa7SThomas Hellström 1192ef6efa7SThomas Hellström GEM_BUG_ON(GRAPHICS_VER(vm->i915) < 8); 1202ef6efa7SThomas Hellström ptep = (typeof(ptep))ggtt->gsm + (ggtt_total_entries(ggtt) - 1); 1212ef6efa7SThomas Hellström return readq(ptep); 1222ef6efa7SThomas Hellström } 1232ef6efa7SThomas Hellström 1248d2f683fSImre Deak /** 1258d2f683fSImre Deak * i915_ggtt_suspend_vm - Suspend the memory mappings for a GGTT or DPT VM 1268d2f683fSImre Deak * @vm: The VM to suspend the mappings for 1278d2f683fSImre Deak * 1288d2f683fSImre Deak * Suspend the memory mappings for all objects mapped to HW via the GGTT or a 1298d2f683fSImre Deak * DPT page table. 1308d2f683fSImre Deak */ 1318d2f683fSImre Deak void i915_ggtt_suspend_vm(struct i915_address_space *vm) 1322c86e55dSMatthew Auld { 133bffa18ddSChris Wilson struct i915_vma *vma, *vn; 134e1a7ab4fSThomas Hellström int save_skip_rewrite; 135e3793468SChris Wilson 1368d2f683fSImre Deak drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt); 1378d2f683fSImre Deak 1380f341974SMaarten Lankhorst retry: 1390f341974SMaarten Lankhorst i915_gem_drain_freed_objects(vm->i915); 1400f341974SMaarten Lankhorst 1418d2f683fSImre Deak mutex_lock(&vm->mutex); 142bffa18ddSChris Wilson 143e1a7ab4fSThomas Hellström /* 144e1a7ab4fSThomas Hellström * Skip rewriting PTE on VMA unbind. 145e1a7ab4fSThomas Hellström * FIXME: Use an argument to i915_vma_unbind() instead? 146e1a7ab4fSThomas Hellström */ 147e1a7ab4fSThomas Hellström save_skip_rewrite = vm->skip_pte_rewrite; 148e1a7ab4fSThomas Hellström vm->skip_pte_rewrite = true; 149bffa18ddSChris Wilson 1508d2f683fSImre Deak list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) { 1510f341974SMaarten Lankhorst struct drm_i915_gem_object *obj = vma->obj; 152e3793468SChris Wilson 1530f341974SMaarten Lankhorst GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); 1540f341974SMaarten Lankhorst 1550f341974SMaarten Lankhorst if (i915_vma_is_pinned(vma) || !i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) 156bffa18ddSChris Wilson continue; 157bffa18ddSChris Wilson 1580f341974SMaarten Lankhorst /* unlikely to race when GPU is idle, so no worry about slowpath.. */ 1590f341974SMaarten Lankhorst if (WARN_ON(!i915_gem_object_trylock(obj, NULL))) { 1600f341974SMaarten Lankhorst /* 1610f341974SMaarten Lankhorst * No dead objects should appear here, GPU should be 1620f341974SMaarten Lankhorst * completely idle, and userspace suspended 1630f341974SMaarten Lankhorst */ 1640f341974SMaarten Lankhorst i915_gem_object_get(obj); 1650f341974SMaarten Lankhorst 1660f341974SMaarten Lankhorst mutex_unlock(&vm->mutex); 1670f341974SMaarten Lankhorst 1680f341974SMaarten Lankhorst i915_gem_object_lock(obj, NULL); 169e1a7ab4fSThomas Hellström GEM_WARN_ON(i915_vma_unbind(vma)); 1700f341974SMaarten Lankhorst i915_gem_object_unlock(obj); 1710f341974SMaarten Lankhorst i915_gem_object_put(obj); 172e1a7ab4fSThomas Hellström 173e1a7ab4fSThomas Hellström vm->skip_pte_rewrite = save_skip_rewrite; 1740f341974SMaarten Lankhorst goto retry; 1750f341974SMaarten Lankhorst } 1760f341974SMaarten Lankhorst 177bffa18ddSChris Wilson if (!i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) { 1780f341974SMaarten Lankhorst i915_vma_wait_for_bind(vma); 1790f341974SMaarten Lankhorst 1802f6b90daSThomas Hellström __i915_vma_evict(vma, false); 181bffa18ddSChris Wilson drm_mm_remove_node(&vma->node); 182bffa18ddSChris Wilson } 1830f341974SMaarten Lankhorst 1840f341974SMaarten Lankhorst i915_gem_object_unlock(obj); 185bffa18ddSChris Wilson } 186bffa18ddSChris Wilson 1872ef6efa7SThomas Hellström if (!suspend_retains_ptes(vm)) 1888d2f683fSImre Deak vm->clear_range(vm, 0, vm->total); 1892ef6efa7SThomas Hellström else 1902ef6efa7SThomas Hellström i915_vm_to_ggtt(vm)->probed_pte = read_last_pte(vm); 191bffa18ddSChris Wilson 192e1a7ab4fSThomas Hellström vm->skip_pte_rewrite = save_skip_rewrite; 1938d2f683fSImre Deak 1948d2f683fSImre Deak mutex_unlock(&vm->mutex); 1958d2f683fSImre Deak } 1968d2f683fSImre Deak 1978d2f683fSImre Deak void i915_ggtt_suspend(struct i915_ggtt *ggtt) 1988d2f683fSImre Deak { 1998d2f683fSImre Deak i915_ggtt_suspend_vm(&ggtt->vm); 2008d2f683fSImre Deak ggtt->invalidate(ggtt); 2012c86e55dSMatthew Auld 2022c86e55dSMatthew Auld intel_gt_check_and_clear_faults(ggtt->vm.gt); 2032c86e55dSMatthew Auld } 2042c86e55dSMatthew Auld 2052c86e55dSMatthew Auld void gen6_ggtt_invalidate(struct i915_ggtt *ggtt) 2062c86e55dSMatthew Auld { 2072c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 2082c86e55dSMatthew Auld 2092c86e55dSMatthew Auld spin_lock_irq(&uncore->lock); 2102c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); 2112c86e55dSMatthew Auld intel_uncore_read_fw(uncore, GFX_FLSH_CNTL_GEN6); 2122c86e55dSMatthew Auld spin_unlock_irq(&uncore->lock); 2132c86e55dSMatthew Auld } 2142c86e55dSMatthew Auld 2159ce07d94SLucas De Marchi static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) 2162c86e55dSMatthew Auld { 2172c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 2182c86e55dSMatthew Auld 2192c86e55dSMatthew Auld /* 2202c86e55dSMatthew Auld * Note that as an uncached mmio write, this will flush the 2212c86e55dSMatthew Auld * WCB of the writes into the GGTT before it triggers the invalidate. 2222c86e55dSMatthew Auld */ 2232c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); 2242c86e55dSMatthew Auld } 2252c86e55dSMatthew Auld 2262c86e55dSMatthew Auld static void guc_ggtt_invalidate(struct i915_ggtt *ggtt) 2272c86e55dSMatthew Auld { 2282c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 2292c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 2302c86e55dSMatthew Auld 2312c86e55dSMatthew Auld gen8_ggtt_invalidate(ggtt); 2322c86e55dSMatthew Auld 233c816723bSLucas De Marchi if (GRAPHICS_VER(i915) >= 12) 2342c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GEN12_GUC_TLB_INV_CR, 2352c86e55dSMatthew Auld GEN12_GUC_TLB_INV_CR_INVALIDATE); 2362c86e55dSMatthew Auld else 2372c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE); 2382c86e55dSMatthew Auld } 2392c86e55dSMatthew Auld 24033e7a975SVille Syrjälä u64 gen8_ggtt_pte_encode(dma_addr_t addr, 24169edc390SDaniele Ceraolo Spurio enum i915_cache_level level, 24269edc390SDaniele Ceraolo Spurio u32 flags) 24369edc390SDaniele Ceraolo Spurio { 2445f978167SMichael Cheng gen8_pte_t pte = addr | GEN8_PAGE_PRESENT; 245e762bdf5SMatthew Auld 246e762bdf5SMatthew Auld if (flags & PTE_LM) 247e762bdf5SMatthew Auld pte |= GEN12_GGTT_PTE_LM; 248e762bdf5SMatthew Auld 249e762bdf5SMatthew Auld return pte; 25069edc390SDaniele Ceraolo Spurio } 25169edc390SDaniele Ceraolo Spurio 2529ce07d94SLucas De Marchi static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) 2539ce07d94SLucas De Marchi { 2549ce07d94SLucas De Marchi writeq(pte, addr); 2559ce07d94SLucas De Marchi } 2569ce07d94SLucas De Marchi 2579ce07d94SLucas De Marchi static void gen8_ggtt_insert_page(struct i915_address_space *vm, 2589ce07d94SLucas De Marchi dma_addr_t addr, 2599ce07d94SLucas De Marchi u64 offset, 2609ce07d94SLucas De Marchi enum i915_cache_level level, 2619ce07d94SLucas De Marchi u32 flags) 2629ce07d94SLucas De Marchi { 2639ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2649ce07d94SLucas De Marchi gen8_pte_t __iomem *pte = 2659ce07d94SLucas De Marchi (gen8_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; 2669ce07d94SLucas De Marchi 2679ce07d94SLucas De Marchi gen8_set_pte(pte, gen8_ggtt_pte_encode(addr, level, flags)); 2689ce07d94SLucas De Marchi 2699ce07d94SLucas De Marchi ggtt->invalidate(ggtt); 2709ce07d94SLucas De Marchi } 2719ce07d94SLucas De Marchi 2729ce07d94SLucas De Marchi static void gen8_ggtt_insert_entries(struct i915_address_space *vm, 2739ce07d94SLucas De Marchi struct i915_vma_resource *vma_res, 2749ce07d94SLucas De Marchi enum i915_cache_level level, 2759ce07d94SLucas De Marchi u32 flags) 2769ce07d94SLucas De Marchi { 2779ce07d94SLucas De Marchi const gen8_pte_t pte_encode = gen8_ggtt_pte_encode(0, level, flags); 2789ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2799ce07d94SLucas De Marchi gen8_pte_t __iomem *gte; 2809ce07d94SLucas De Marchi gen8_pte_t __iomem *end; 2819ce07d94SLucas De Marchi struct sgt_iter iter; 2829ce07d94SLucas De Marchi dma_addr_t addr; 2839ce07d94SLucas De Marchi 2849ce07d94SLucas De Marchi /* 2859ce07d94SLucas De Marchi * Note that we ignore PTE_READ_ONLY here. The caller must be careful 2869ce07d94SLucas De Marchi * not to allow the user to override access to a read only page. 2879ce07d94SLucas De Marchi */ 2889ce07d94SLucas De Marchi 2899ce07d94SLucas De Marchi gte = (gen8_pte_t __iomem *)ggtt->gsm; 2909ce07d94SLucas De Marchi gte += vma_res->start / I915_GTT_PAGE_SIZE; 2919ce07d94SLucas De Marchi end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE; 2929ce07d94SLucas De Marchi 2939ce07d94SLucas De Marchi for_each_sgt_daddr(addr, iter, vma_res->bi.pages) 2949ce07d94SLucas De Marchi gen8_set_pte(gte++, pte_encode | addr); 2959ce07d94SLucas De Marchi GEM_BUG_ON(gte > end); 2969ce07d94SLucas De Marchi 2979ce07d94SLucas De Marchi /* Fill the allocated but "unused" space beyond the end of the buffer */ 2989ce07d94SLucas De Marchi while (gte < end) 2999ce07d94SLucas De Marchi gen8_set_pte(gte++, vm->scratch[0]->encode); 3009ce07d94SLucas De Marchi 3019ce07d94SLucas De Marchi /* 3029ce07d94SLucas De Marchi * We want to flush the TLBs only after we're certain all the PTE 3039ce07d94SLucas De Marchi * updates have finished. 3049ce07d94SLucas De Marchi */ 3059ce07d94SLucas De Marchi ggtt->invalidate(ggtt); 3069ce07d94SLucas De Marchi } 3079ce07d94SLucas De Marchi 3089ce07d94SLucas De Marchi static void gen6_ggtt_insert_page(struct i915_address_space *vm, 3099ce07d94SLucas De Marchi dma_addr_t addr, 3109ce07d94SLucas De Marchi u64 offset, 3119ce07d94SLucas De Marchi enum i915_cache_level level, 3129ce07d94SLucas De Marchi u32 flags) 3139ce07d94SLucas De Marchi { 3149ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 3159ce07d94SLucas De Marchi gen6_pte_t __iomem *pte = 3169ce07d94SLucas De Marchi (gen6_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; 3179ce07d94SLucas De Marchi 3189ce07d94SLucas De Marchi iowrite32(vm->pte_encode(addr, level, flags), pte); 3199ce07d94SLucas De Marchi 3209ce07d94SLucas De Marchi ggtt->invalidate(ggtt); 3219ce07d94SLucas De Marchi } 3229ce07d94SLucas De Marchi 3239ce07d94SLucas De Marchi /* 3249ce07d94SLucas De Marchi * Binds an object into the global gtt with the specified cache level. 3259ce07d94SLucas De Marchi * The object will be accessible to the GPU via commands whose operands 3269ce07d94SLucas De Marchi * reference offsets within the global GTT as well as accessible by the GPU 3279ce07d94SLucas De Marchi * through the GMADR mapped BAR (i915->mm.gtt->gtt). 3289ce07d94SLucas De Marchi */ 3299ce07d94SLucas De Marchi static void gen6_ggtt_insert_entries(struct i915_address_space *vm, 3309ce07d94SLucas De Marchi struct i915_vma_resource *vma_res, 3319ce07d94SLucas De Marchi enum i915_cache_level level, 3329ce07d94SLucas De Marchi u32 flags) 3339ce07d94SLucas De Marchi { 3349ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 3359ce07d94SLucas De Marchi gen6_pte_t __iomem *gte; 3369ce07d94SLucas De Marchi gen6_pte_t __iomem *end; 3379ce07d94SLucas De Marchi struct sgt_iter iter; 3389ce07d94SLucas De Marchi dma_addr_t addr; 3399ce07d94SLucas De Marchi 3409ce07d94SLucas De Marchi gte = (gen6_pte_t __iomem *)ggtt->gsm; 3419ce07d94SLucas De Marchi gte += vma_res->start / I915_GTT_PAGE_SIZE; 3429ce07d94SLucas De Marchi end = gte + vma_res->node_size / I915_GTT_PAGE_SIZE; 3439ce07d94SLucas De Marchi 3449ce07d94SLucas De Marchi for_each_sgt_daddr(addr, iter, vma_res->bi.pages) 3459ce07d94SLucas De Marchi iowrite32(vm->pte_encode(addr, level, flags), gte++); 3469ce07d94SLucas De Marchi GEM_BUG_ON(gte > end); 3479ce07d94SLucas De Marchi 3489ce07d94SLucas De Marchi /* Fill the allocated but "unused" space beyond the end of the buffer */ 3499ce07d94SLucas De Marchi while (gte < end) 3509ce07d94SLucas De Marchi iowrite32(vm->scratch[0]->encode, gte++); 3519ce07d94SLucas De Marchi 3529ce07d94SLucas De Marchi /* 3539ce07d94SLucas De Marchi * We want to flush the TLBs only after we're certain all the PTE 3549ce07d94SLucas De Marchi * updates have finished. 3559ce07d94SLucas De Marchi */ 3569ce07d94SLucas De Marchi ggtt->invalidate(ggtt); 3579ce07d94SLucas De Marchi } 3589ce07d94SLucas De Marchi 3599ce07d94SLucas De Marchi static void nop_clear_range(struct i915_address_space *vm, 3609ce07d94SLucas De Marchi u64 start, u64 length) 3619ce07d94SLucas De Marchi { 3629ce07d94SLucas De Marchi } 3639ce07d94SLucas De Marchi 3649ce07d94SLucas De Marchi static void gen8_ggtt_clear_range(struct i915_address_space *vm, 3659ce07d94SLucas De Marchi u64 start, u64 length) 3669ce07d94SLucas De Marchi { 3679ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 3689ce07d94SLucas De Marchi unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 3699ce07d94SLucas De Marchi unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 3709ce07d94SLucas De Marchi const gen8_pte_t scratch_pte = vm->scratch[0]->encode; 3719ce07d94SLucas De Marchi gen8_pte_t __iomem *gtt_base = 3729ce07d94SLucas De Marchi (gen8_pte_t __iomem *)ggtt->gsm + first_entry; 3739ce07d94SLucas De Marchi const int max_entries = ggtt_total_entries(ggtt) - first_entry; 3749ce07d94SLucas De Marchi int i; 3759ce07d94SLucas De Marchi 3769ce07d94SLucas De Marchi if (WARN(num_entries > max_entries, 3779ce07d94SLucas De Marchi "First entry = %d; Num entries = %d (max=%d)\n", 3789ce07d94SLucas De Marchi first_entry, num_entries, max_entries)) 3799ce07d94SLucas De Marchi num_entries = max_entries; 3809ce07d94SLucas De Marchi 3819ce07d94SLucas De Marchi for (i = 0; i < num_entries; i++) 3829ce07d94SLucas De Marchi gen8_set_pte(>t_base[i], scratch_pte); 3839ce07d94SLucas De Marchi } 3849ce07d94SLucas De Marchi 3859ce07d94SLucas De Marchi static void bxt_vtd_ggtt_wa(struct i915_address_space *vm) 3869ce07d94SLucas De Marchi { 3879ce07d94SLucas De Marchi /* 3889ce07d94SLucas De Marchi * Make sure the internal GAM fifo has been cleared of all GTT 3899ce07d94SLucas De Marchi * writes before exiting stop_machine(). This guarantees that 3909ce07d94SLucas De Marchi * any aperture accesses waiting to start in another process 3919ce07d94SLucas De Marchi * cannot back up behind the GTT writes causing a hang. 3929ce07d94SLucas De Marchi * The register can be any arbitrary GAM register. 3939ce07d94SLucas De Marchi */ 3949ce07d94SLucas De Marchi intel_uncore_posting_read_fw(vm->gt->uncore, GFX_FLSH_CNTL_GEN6); 3959ce07d94SLucas De Marchi } 3969ce07d94SLucas De Marchi 3979ce07d94SLucas De Marchi struct insert_page { 3989ce07d94SLucas De Marchi struct i915_address_space *vm; 3999ce07d94SLucas De Marchi dma_addr_t addr; 4009ce07d94SLucas De Marchi u64 offset; 4019ce07d94SLucas De Marchi enum i915_cache_level level; 4029ce07d94SLucas De Marchi }; 4039ce07d94SLucas De Marchi 4049ce07d94SLucas De Marchi static int bxt_vtd_ggtt_insert_page__cb(void *_arg) 4059ce07d94SLucas De Marchi { 4069ce07d94SLucas De Marchi struct insert_page *arg = _arg; 4079ce07d94SLucas De Marchi 4089ce07d94SLucas De Marchi gen8_ggtt_insert_page(arg->vm, arg->addr, arg->offset, arg->level, 0); 4099ce07d94SLucas De Marchi bxt_vtd_ggtt_wa(arg->vm); 4109ce07d94SLucas De Marchi 4119ce07d94SLucas De Marchi return 0; 4129ce07d94SLucas De Marchi } 4139ce07d94SLucas De Marchi 4149ce07d94SLucas De Marchi static void bxt_vtd_ggtt_insert_page__BKL(struct i915_address_space *vm, 4159ce07d94SLucas De Marchi dma_addr_t addr, 4169ce07d94SLucas De Marchi u64 offset, 4179ce07d94SLucas De Marchi enum i915_cache_level level, 4189ce07d94SLucas De Marchi u32 unused) 4199ce07d94SLucas De Marchi { 4209ce07d94SLucas De Marchi struct insert_page arg = { vm, addr, offset, level }; 4219ce07d94SLucas De Marchi 4229ce07d94SLucas De Marchi stop_machine(bxt_vtd_ggtt_insert_page__cb, &arg, NULL); 4239ce07d94SLucas De Marchi } 4249ce07d94SLucas De Marchi 4259ce07d94SLucas De Marchi struct insert_entries { 4269ce07d94SLucas De Marchi struct i915_address_space *vm; 4279ce07d94SLucas De Marchi struct i915_vma_resource *vma_res; 4289ce07d94SLucas De Marchi enum i915_cache_level level; 4299ce07d94SLucas De Marchi u32 flags; 4309ce07d94SLucas De Marchi }; 4319ce07d94SLucas De Marchi 4329ce07d94SLucas De Marchi static int bxt_vtd_ggtt_insert_entries__cb(void *_arg) 4339ce07d94SLucas De Marchi { 4349ce07d94SLucas De Marchi struct insert_entries *arg = _arg; 4359ce07d94SLucas De Marchi 4369ce07d94SLucas De Marchi gen8_ggtt_insert_entries(arg->vm, arg->vma_res, arg->level, arg->flags); 4379ce07d94SLucas De Marchi bxt_vtd_ggtt_wa(arg->vm); 4389ce07d94SLucas De Marchi 4399ce07d94SLucas De Marchi return 0; 4409ce07d94SLucas De Marchi } 4419ce07d94SLucas De Marchi 4429ce07d94SLucas De Marchi static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm, 4439ce07d94SLucas De Marchi struct i915_vma_resource *vma_res, 4449ce07d94SLucas De Marchi enum i915_cache_level level, 4459ce07d94SLucas De Marchi u32 flags) 4469ce07d94SLucas De Marchi { 4479ce07d94SLucas De Marchi struct insert_entries arg = { vm, vma_res, level, flags }; 4489ce07d94SLucas De Marchi 4499ce07d94SLucas De Marchi stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL); 4509ce07d94SLucas De Marchi } 4519ce07d94SLucas De Marchi 4529ce07d94SLucas De Marchi static void gen6_ggtt_clear_range(struct i915_address_space *vm, 4539ce07d94SLucas De Marchi u64 start, u64 length) 4549ce07d94SLucas De Marchi { 4559ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 4569ce07d94SLucas De Marchi unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 4579ce07d94SLucas De Marchi unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 4589ce07d94SLucas De Marchi gen6_pte_t scratch_pte, __iomem *gtt_base = 4599ce07d94SLucas De Marchi (gen6_pte_t __iomem *)ggtt->gsm + first_entry; 4609ce07d94SLucas De Marchi const int max_entries = ggtt_total_entries(ggtt) - first_entry; 4619ce07d94SLucas De Marchi int i; 4629ce07d94SLucas De Marchi 4639ce07d94SLucas De Marchi if (WARN(num_entries > max_entries, 4649ce07d94SLucas De Marchi "First entry = %d; Num entries = %d (max=%d)\n", 4659ce07d94SLucas De Marchi first_entry, num_entries, max_entries)) 4669ce07d94SLucas De Marchi num_entries = max_entries; 4679ce07d94SLucas De Marchi 4689ce07d94SLucas De Marchi scratch_pte = vm->scratch[0]->encode; 4699ce07d94SLucas De Marchi for (i = 0; i < num_entries; i++) 4709ce07d94SLucas De Marchi iowrite32(scratch_pte, >t_base[i]); 4719ce07d94SLucas De Marchi } 4729ce07d94SLucas De Marchi 4737a5c9223SCasey Bowman void intel_ggtt_bind_vma(struct i915_address_space *vm, 474cd0452aaSChris Wilson struct i915_vm_pt_stash *stash, 47539a2bd34SThomas Hellström struct i915_vma_resource *vma_res, 4762c86e55dSMatthew Auld enum i915_cache_level cache_level, 4772c86e55dSMatthew Auld u32 flags) 4782c86e55dSMatthew Auld { 4792c86e55dSMatthew Auld u32 pte_flags; 4802c86e55dSMatthew Auld 48139a2bd34SThomas Hellström if (vma_res->bound_flags & (~flags & I915_VMA_BIND_MASK)) 482cd0452aaSChris Wilson return; 483bf0840cdSChris Wilson 48439a2bd34SThomas Hellström vma_res->bound_flags |= flags; 48539a2bd34SThomas Hellström 4862c86e55dSMatthew Auld /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ 4872c86e55dSMatthew Auld pte_flags = 0; 48839a2bd34SThomas Hellström if (vma_res->bi.readonly) 4892c86e55dSMatthew Auld pte_flags |= PTE_READ_ONLY; 49039a2bd34SThomas Hellström if (vma_res->bi.lmem) 491e762bdf5SMatthew Auld pte_flags |= PTE_LM; 4922c86e55dSMatthew Auld 49339a2bd34SThomas Hellström vm->insert_entries(vm, vma_res, cache_level, pte_flags); 49439a2bd34SThomas Hellström vma_res->page_sizes_gtt = I915_GTT_PAGE_SIZE; 4952c86e55dSMatthew Auld } 4962c86e55dSMatthew Auld 4977a5c9223SCasey Bowman void intel_ggtt_unbind_vma(struct i915_address_space *vm, 49839a2bd34SThomas Hellström struct i915_vma_resource *vma_res) 4992c86e55dSMatthew Auld { 50039a2bd34SThomas Hellström vm->clear_range(vm, vma_res->start, vma_res->vma_size); 5012c86e55dSMatthew Auld } 5022c86e55dSMatthew Auld 5032c86e55dSMatthew Auld static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt) 5042c86e55dSMatthew Auld { 5052c86e55dSMatthew Auld u64 size; 5062c86e55dSMatthew Auld int ret; 5072c86e55dSMatthew Auld 50834bbfde6SDaniele Ceraolo Spurio if (!intel_uc_uses_guc(&ggtt->vm.gt->uc)) 5092c86e55dSMatthew Auld return 0; 5102c86e55dSMatthew Auld 5112c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP); 5122c86e55dSMatthew Auld size = ggtt->vm.total - GUC_GGTT_TOP; 5132c86e55dSMatthew Auld 5147e00897bSMaarten Lankhorst ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, size, 5152c86e55dSMatthew Auld GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE, 5162c86e55dSMatthew Auld PIN_NOEVICT); 5172c86e55dSMatthew Auld if (ret) 51852ce7074SWambui Karuga drm_dbg(&ggtt->vm.i915->drm, 51952ce7074SWambui Karuga "Failed to reserve top of GGTT for GuC\n"); 5202c86e55dSMatthew Auld 5212c86e55dSMatthew Auld return ret; 5222c86e55dSMatthew Auld } 5232c86e55dSMatthew Auld 5242c86e55dSMatthew Auld static void ggtt_release_guc_top(struct i915_ggtt *ggtt) 5252c86e55dSMatthew Auld { 5262c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->uc_fw)) 5272c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->uc_fw); 5282c86e55dSMatthew Auld } 5292c86e55dSMatthew Auld 5302c86e55dSMatthew Auld static void cleanup_init_ggtt(struct i915_ggtt *ggtt) 5312c86e55dSMatthew Auld { 5322c86e55dSMatthew Auld ggtt_release_guc_top(ggtt); 5332c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->error_capture)) 5342c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->error_capture); 535742379c0SChris Wilson mutex_destroy(&ggtt->error_mutex); 5362c86e55dSMatthew Auld } 5372c86e55dSMatthew Auld 5382c86e55dSMatthew Auld static int init_ggtt(struct i915_ggtt *ggtt) 5392c86e55dSMatthew Auld { 5402c86e55dSMatthew Auld /* 5412c86e55dSMatthew Auld * Let GEM Manage all of the aperture. 5422c86e55dSMatthew Auld * 5432c86e55dSMatthew Auld * However, leave one page at the end still bound to the scratch page. 5442c86e55dSMatthew Auld * There are a number of places where the hardware apparently prefetches 5452c86e55dSMatthew Auld * past the end of the object, and we've seen multiple hangs with the 5462c86e55dSMatthew Auld * GPU head pointer stuck in a batchbuffer bound at the last page of the 5472c86e55dSMatthew Auld * aperture. One page should be enough to keep any prefetching inside 5482c86e55dSMatthew Auld * of the aperture. 5492c86e55dSMatthew Auld */ 5502c86e55dSMatthew Auld unsigned long hole_start, hole_end; 5512c86e55dSMatthew Auld struct drm_mm_node *entry; 5522c86e55dSMatthew Auld int ret; 5532c86e55dSMatthew Auld 5542ef6efa7SThomas Hellström ggtt->pte_lost = true; 5552ef6efa7SThomas Hellström 5562c86e55dSMatthew Auld /* 5572c86e55dSMatthew Auld * GuC requires all resources that we're sharing with it to be placed in 5582c86e55dSMatthew Auld * non-WOPCM memory. If GuC is not present or not in use we still need a 5592c86e55dSMatthew Auld * small bias as ring wraparound at offset 0 sometimes hangs. No idea 5602c86e55dSMatthew Auld * why. 5612c86e55dSMatthew Auld */ 5622c86e55dSMatthew Auld ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE, 5632c86e55dSMatthew Auld intel_wopcm_guc_size(&ggtt->vm.i915->wopcm)); 5642c86e55dSMatthew Auld 5652c86e55dSMatthew Auld ret = intel_vgt_balloon(ggtt); 5662c86e55dSMatthew Auld if (ret) 5672c86e55dSMatthew Auld return ret; 5682c86e55dSMatthew Auld 569742379c0SChris Wilson mutex_init(&ggtt->error_mutex); 5702c86e55dSMatthew Auld if (ggtt->mappable_end) { 571489140b5SChris Wilson /* 572489140b5SChris Wilson * Reserve a mappable slot for our lockless error capture. 573489140b5SChris Wilson * 574489140b5SChris Wilson * We strongly prefer taking address 0x0 in order to protect 575489140b5SChris Wilson * other critical buffers against accidental overwrites, 576489140b5SChris Wilson * as writing to address 0 is a very common mistake. 577489140b5SChris Wilson * 578489140b5SChris Wilson * Since 0 may already be in use by the system (e.g. the BIOS 579489140b5SChris Wilson * framebuffer), we let the reservation fail quietly and hope 580489140b5SChris Wilson * 0 remains reserved always. 581489140b5SChris Wilson * 582489140b5SChris Wilson * If we fail to reserve 0, and then fail to find any space 583489140b5SChris Wilson * for an error-capture, remain silent. We can afford not 584489140b5SChris Wilson * to reserve an error_capture node as we have fallback 585489140b5SChris Wilson * paths, and we trust that 0 will remain reserved. However, 586489140b5SChris Wilson * the only likely reason for failure to insert is a driver 587489140b5SChris Wilson * bug, which we expect to cause other failures... 588489140b5SChris Wilson */ 589489140b5SChris Wilson ggtt->error_capture.size = I915_GTT_PAGE_SIZE; 590489140b5SChris Wilson ggtt->error_capture.color = I915_COLOR_UNEVICTABLE; 591489140b5SChris Wilson if (drm_mm_reserve_node(&ggtt->vm.mm, &ggtt->error_capture)) 592489140b5SChris Wilson drm_mm_insert_node_in_range(&ggtt->vm.mm, 5932c86e55dSMatthew Auld &ggtt->error_capture, 594489140b5SChris Wilson ggtt->error_capture.size, 0, 595489140b5SChris Wilson ggtt->error_capture.color, 5962c86e55dSMatthew Auld 0, ggtt->mappable_end, 5972c86e55dSMatthew Auld DRM_MM_INSERT_LOW); 5982c86e55dSMatthew Auld } 599489140b5SChris Wilson if (drm_mm_node_allocated(&ggtt->error_capture)) 600489140b5SChris Wilson drm_dbg(&ggtt->vm.i915->drm, 601489140b5SChris Wilson "Reserved GGTT:[%llx, %llx] for use by error capture\n", 602489140b5SChris Wilson ggtt->error_capture.start, 603489140b5SChris Wilson ggtt->error_capture.start + ggtt->error_capture.size); 6042c86e55dSMatthew Auld 6052c86e55dSMatthew Auld /* 6062c86e55dSMatthew Auld * The upper portion of the GuC address space has a sizeable hole 6072c86e55dSMatthew Auld * (several MB) that is inaccessible by GuC. Reserve this range within 6082c86e55dSMatthew Auld * GGTT as it can comfortably hold GuC/HuC firmware images. 6092c86e55dSMatthew Auld */ 6102c86e55dSMatthew Auld ret = ggtt_reserve_guc_top(ggtt); 6112c86e55dSMatthew Auld if (ret) 6122c86e55dSMatthew Auld goto err; 6132c86e55dSMatthew Auld 6142c86e55dSMatthew Auld /* Clear any non-preallocated blocks */ 6152c86e55dSMatthew Auld drm_mm_for_each_hole(entry, &ggtt->vm.mm, hole_start, hole_end) { 616489140b5SChris Wilson drm_dbg(&ggtt->vm.i915->drm, 61752ce7074SWambui Karuga "clearing unused GTT space: [%lx, %lx]\n", 6182c86e55dSMatthew Auld hole_start, hole_end); 6192c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, hole_start, 6202c86e55dSMatthew Auld hole_end - hole_start); 6212c86e55dSMatthew Auld } 6222c86e55dSMatthew Auld 6232c86e55dSMatthew Auld /* And finally clear the reserved guard page */ 6242c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, ggtt->vm.total - PAGE_SIZE, PAGE_SIZE); 6252c86e55dSMatthew Auld 6262c86e55dSMatthew Auld return 0; 6272c86e55dSMatthew Auld 6282c86e55dSMatthew Auld err: 6292c86e55dSMatthew Auld cleanup_init_ggtt(ggtt); 6302c86e55dSMatthew Auld return ret; 6312c86e55dSMatthew Auld } 6322c86e55dSMatthew Auld 633cd0452aaSChris Wilson static void aliasing_gtt_bind_vma(struct i915_address_space *vm, 634cd0452aaSChris Wilson struct i915_vm_pt_stash *stash, 63539a2bd34SThomas Hellström struct i915_vma_resource *vma_res, 6362c86e55dSMatthew Auld enum i915_cache_level cache_level, 6372c86e55dSMatthew Auld u32 flags) 6382c86e55dSMatthew Auld { 6392c86e55dSMatthew Auld u32 pte_flags; 6402c86e55dSMatthew Auld 6412c86e55dSMatthew Auld /* Currently applicable only to VLV */ 6422c86e55dSMatthew Auld pte_flags = 0; 64339a2bd34SThomas Hellström if (vma_res->bi.readonly) 6442c86e55dSMatthew Auld pte_flags |= PTE_READ_ONLY; 6452c86e55dSMatthew Auld 646cd0452aaSChris Wilson if (flags & I915_VMA_LOCAL_BIND) 647cd0452aaSChris Wilson ppgtt_bind_vma(&i915_vm_to_ggtt(vm)->alias->vm, 64839a2bd34SThomas Hellström stash, vma_res, cache_level, flags); 6492c86e55dSMatthew Auld 650c0e60347SChris Wilson if (flags & I915_VMA_GLOBAL_BIND) 65139a2bd34SThomas Hellström vm->insert_entries(vm, vma_res, cache_level, pte_flags); 65239a2bd34SThomas Hellström 65339a2bd34SThomas Hellström vma_res->bound_flags |= flags; 6542c86e55dSMatthew Auld } 6552c86e55dSMatthew Auld 65612b07256SChris Wilson static void aliasing_gtt_unbind_vma(struct i915_address_space *vm, 65739a2bd34SThomas Hellström struct i915_vma_resource *vma_res) 6582c86e55dSMatthew Auld { 65939a2bd34SThomas Hellström if (vma_res->bound_flags & I915_VMA_GLOBAL_BIND) 66039a2bd34SThomas Hellström vm->clear_range(vm, vma_res->start, vma_res->vma_size); 6612c86e55dSMatthew Auld 66239a2bd34SThomas Hellström if (vma_res->bound_flags & I915_VMA_LOCAL_BIND) 66339a2bd34SThomas Hellström ppgtt_unbind_vma(&i915_vm_to_ggtt(vm)->alias->vm, vma_res); 6642c86e55dSMatthew Auld } 6652c86e55dSMatthew Auld 6662c86e55dSMatthew Auld static int init_aliasing_ppgtt(struct i915_ggtt *ggtt) 6672c86e55dSMatthew Auld { 668cd0452aaSChris Wilson struct i915_vm_pt_stash stash = {}; 6692c86e55dSMatthew Auld struct i915_ppgtt *ppgtt; 6702c86e55dSMatthew Auld int err; 6712c86e55dSMatthew Auld 672a259cc14SThomas Hellström ppgtt = i915_ppgtt_create(ggtt->vm.gt, 0); 6732c86e55dSMatthew Auld if (IS_ERR(ppgtt)) 6742c86e55dSMatthew Auld return PTR_ERR(ppgtt); 6752c86e55dSMatthew Auld 6762c86e55dSMatthew Auld if (GEM_WARN_ON(ppgtt->vm.total < ggtt->vm.total)) { 6772c86e55dSMatthew Auld err = -ENODEV; 6782c86e55dSMatthew Auld goto err_ppgtt; 6792c86e55dSMatthew Auld } 6802c86e55dSMatthew Auld 681cd0452aaSChris Wilson err = i915_vm_alloc_pt_stash(&ppgtt->vm, &stash, ggtt->vm.total); 682cd0452aaSChris Wilson if (err) 683cd0452aaSChris Wilson goto err_ppgtt; 684cd0452aaSChris Wilson 68526ad4f8bSMaarten Lankhorst i915_gem_object_lock(ppgtt->vm.scratch[0], NULL); 686529b9ec8SMatthew Auld err = i915_vm_map_pt_stash(&ppgtt->vm, &stash); 68726ad4f8bSMaarten Lankhorst i915_gem_object_unlock(ppgtt->vm.scratch[0]); 68889351925SChris Wilson if (err) 68989351925SChris Wilson goto err_stash; 69089351925SChris Wilson 6912c86e55dSMatthew Auld /* 6922c86e55dSMatthew Auld * Note we only pre-allocate as far as the end of the global 6932c86e55dSMatthew Auld * GTT. On 48b / 4-level page-tables, the difference is very, 6942c86e55dSMatthew Auld * very significant! We have to preallocate as GVT/vgpu does 6952c86e55dSMatthew Auld * not like the page directory disappearing. 6962c86e55dSMatthew Auld */ 697cd0452aaSChris Wilson ppgtt->vm.allocate_va_range(&ppgtt->vm, &stash, 0, ggtt->vm.total); 6982c86e55dSMatthew Auld 6992c86e55dSMatthew Auld ggtt->alias = ppgtt; 7002c86e55dSMatthew Auld ggtt->vm.bind_async_flags |= ppgtt->vm.bind_async_flags; 7012c86e55dSMatthew Auld 7027a5c9223SCasey Bowman GEM_BUG_ON(ggtt->vm.vma_ops.bind_vma != intel_ggtt_bind_vma); 7032c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = aliasing_gtt_bind_vma; 7042c86e55dSMatthew Auld 7057a5c9223SCasey Bowman GEM_BUG_ON(ggtt->vm.vma_ops.unbind_vma != intel_ggtt_unbind_vma); 7062c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = aliasing_gtt_unbind_vma; 7072c86e55dSMatthew Auld 708cd0452aaSChris Wilson i915_vm_free_pt_stash(&ppgtt->vm, &stash); 7092c86e55dSMatthew Auld return 0; 7102c86e55dSMatthew Auld 71189351925SChris Wilson err_stash: 71289351925SChris Wilson i915_vm_free_pt_stash(&ppgtt->vm, &stash); 7132c86e55dSMatthew Auld err_ppgtt: 7142c86e55dSMatthew Auld i915_vm_put(&ppgtt->vm); 7152c86e55dSMatthew Auld return err; 7162c86e55dSMatthew Auld } 7172c86e55dSMatthew Auld 7182c86e55dSMatthew Auld static void fini_aliasing_ppgtt(struct i915_ggtt *ggtt) 7192c86e55dSMatthew Auld { 7202c86e55dSMatthew Auld struct i915_ppgtt *ppgtt; 7212c86e55dSMatthew Auld 7222c86e55dSMatthew Auld ppgtt = fetch_and_zero(&ggtt->alias); 7232c86e55dSMatthew Auld if (!ppgtt) 7242c86e55dSMatthew Auld return; 7252c86e55dSMatthew Auld 7262c86e55dSMatthew Auld i915_vm_put(&ppgtt->vm); 7272c86e55dSMatthew Auld 7287a5c9223SCasey Bowman ggtt->vm.vma_ops.bind_vma = intel_ggtt_bind_vma; 7297a5c9223SCasey Bowman ggtt->vm.vma_ops.unbind_vma = intel_ggtt_unbind_vma; 7302c86e55dSMatthew Auld } 7312c86e55dSMatthew Auld 7322c86e55dSMatthew Auld int i915_init_ggtt(struct drm_i915_private *i915) 7332c86e55dSMatthew Auld { 7342c86e55dSMatthew Auld int ret; 7352c86e55dSMatthew Auld 736848915c3SMichał Winiarski ret = init_ggtt(to_gt(i915)->ggtt); 7372c86e55dSMatthew Auld if (ret) 7382c86e55dSMatthew Auld return ret; 7392c86e55dSMatthew Auld 7402c86e55dSMatthew Auld if (INTEL_PPGTT(i915) == INTEL_PPGTT_ALIASING) { 741848915c3SMichał Winiarski ret = init_aliasing_ppgtt(to_gt(i915)->ggtt); 7422c86e55dSMatthew Auld if (ret) 743848915c3SMichał Winiarski cleanup_init_ggtt(to_gt(i915)->ggtt); 7442c86e55dSMatthew Auld } 7452c86e55dSMatthew Auld 7462c86e55dSMatthew Auld return 0; 7472c86e55dSMatthew Auld } 7482c86e55dSMatthew Auld 7492c86e55dSMatthew Auld static void ggtt_cleanup_hw(struct i915_ggtt *ggtt) 7502c86e55dSMatthew Auld { 7512c86e55dSMatthew Auld struct i915_vma *vma, *vn; 7522c86e55dSMatthew Auld 7532c86e55dSMatthew Auld flush_workqueue(ggtt->vm.i915->wq); 7540f341974SMaarten Lankhorst i915_gem_drain_freed_objects(ggtt->vm.i915); 7552c86e55dSMatthew Auld 7562c86e55dSMatthew Auld mutex_lock(&ggtt->vm.mutex); 7572c86e55dSMatthew Auld 758e1a7ab4fSThomas Hellström ggtt->vm.skip_pte_rewrite = true; 759e1a7ab4fSThomas Hellström 7600f341974SMaarten Lankhorst list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) { 7610f341974SMaarten Lankhorst struct drm_i915_gem_object *obj = vma->obj; 7620f341974SMaarten Lankhorst bool trylock; 7630f341974SMaarten Lankhorst 7640f341974SMaarten Lankhorst trylock = i915_gem_object_trylock(obj, NULL); 7650f341974SMaarten Lankhorst WARN_ON(!trylock); 7660f341974SMaarten Lankhorst 7672c86e55dSMatthew Auld WARN_ON(__i915_vma_unbind(vma)); 7680f341974SMaarten Lankhorst if (trylock) 7690f341974SMaarten Lankhorst i915_gem_object_unlock(obj); 7700f341974SMaarten Lankhorst } 7712c86e55dSMatthew Auld 7722c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->error_capture)) 7732c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->error_capture); 774742379c0SChris Wilson mutex_destroy(&ggtt->error_mutex); 7752c86e55dSMatthew Auld 7762c86e55dSMatthew Auld ggtt_release_guc_top(ggtt); 7772c86e55dSMatthew Auld intel_vgt_deballoon(ggtt); 7782c86e55dSMatthew Auld 7792c86e55dSMatthew Auld ggtt->vm.cleanup(&ggtt->vm); 7802c86e55dSMatthew Auld 7812c86e55dSMatthew Auld mutex_unlock(&ggtt->vm.mutex); 7822c86e55dSMatthew Auld i915_address_space_fini(&ggtt->vm); 7832c86e55dSMatthew Auld 7842c86e55dSMatthew Auld arch_phys_wc_del(ggtt->mtrr); 7852c86e55dSMatthew Auld 7862c86e55dSMatthew Auld if (ggtt->iomap.size) 7872c86e55dSMatthew Auld io_mapping_fini(&ggtt->iomap); 7882c86e55dSMatthew Auld } 7892c86e55dSMatthew Auld 7902c86e55dSMatthew Auld /** 7912c86e55dSMatthew Auld * i915_ggtt_driver_release - Clean up GGTT hardware initialization 7922c86e55dSMatthew Auld * @i915: i915 device 7932c86e55dSMatthew Auld */ 7942c86e55dSMatthew Auld void i915_ggtt_driver_release(struct drm_i915_private *i915) 7952c86e55dSMatthew Auld { 796848915c3SMichał Winiarski struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 7972c86e55dSMatthew Auld 7980b6bc81dSChris Wilson fini_aliasing_ppgtt(ggtt); 7992c86e55dSMatthew Auld 8000b6bc81dSChris Wilson intel_ggtt_fini_fences(ggtt); 8010b6bc81dSChris Wilson ggtt_cleanup_hw(ggtt); 8022c86e55dSMatthew Auld } 8032c86e55dSMatthew Auld 8044d8151aeSThomas Hellström /** 8054d8151aeSThomas Hellström * i915_ggtt_driver_late_release - Cleanup of GGTT that needs to be done after 8064d8151aeSThomas Hellström * all free objects have been drained. 8074d8151aeSThomas Hellström * @i915: i915 device 8084d8151aeSThomas Hellström */ 8094d8151aeSThomas Hellström void i915_ggtt_driver_late_release(struct drm_i915_private *i915) 8104d8151aeSThomas Hellström { 811848915c3SMichał Winiarski struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 8124d8151aeSThomas Hellström 8134d8151aeSThomas Hellström GEM_WARN_ON(kref_read(&ggtt->vm.resv_ref) != 1); 8144d8151aeSThomas Hellström dma_resv_fini(&ggtt->vm._resv); 8154d8151aeSThomas Hellström } 8164d8151aeSThomas Hellström 8179ce07d94SLucas De Marchi static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) 8189ce07d94SLucas De Marchi { 8199ce07d94SLucas De Marchi snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT; 8209ce07d94SLucas De Marchi snb_gmch_ctl &= SNB_GMCH_GGMS_MASK; 8219ce07d94SLucas De Marchi return snb_gmch_ctl << 20; 8229ce07d94SLucas De Marchi } 8239ce07d94SLucas De Marchi 8249ce07d94SLucas De Marchi static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl) 8259ce07d94SLucas De Marchi { 8269ce07d94SLucas De Marchi bdw_gmch_ctl >>= BDW_GMCH_GGMS_SHIFT; 8279ce07d94SLucas De Marchi bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK; 8289ce07d94SLucas De Marchi if (bdw_gmch_ctl) 8299ce07d94SLucas De Marchi bdw_gmch_ctl = 1 << bdw_gmch_ctl; 8309ce07d94SLucas De Marchi 8319ce07d94SLucas De Marchi #ifdef CONFIG_X86_32 8329ce07d94SLucas De Marchi /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * I915_GTT_PAGE_SIZE */ 8339ce07d94SLucas De Marchi if (bdw_gmch_ctl > 4) 8349ce07d94SLucas De Marchi bdw_gmch_ctl = 4; 8359ce07d94SLucas De Marchi #endif 8369ce07d94SLucas De Marchi 8379ce07d94SLucas De Marchi return bdw_gmch_ctl << 20; 8389ce07d94SLucas De Marchi } 8399ce07d94SLucas De Marchi 8409ce07d94SLucas De Marchi static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl) 8419ce07d94SLucas De Marchi { 8429ce07d94SLucas De Marchi gmch_ctrl >>= SNB_GMCH_GGMS_SHIFT; 8439ce07d94SLucas De Marchi gmch_ctrl &= SNB_GMCH_GGMS_MASK; 8449ce07d94SLucas De Marchi 8459ce07d94SLucas De Marchi if (gmch_ctrl) 8469ce07d94SLucas De Marchi return 1 << (20 + gmch_ctrl); 8479ce07d94SLucas De Marchi 8489ce07d94SLucas De Marchi return 0; 8499ce07d94SLucas De Marchi } 8509ce07d94SLucas De Marchi 8519ce07d94SLucas De Marchi static unsigned int gen6_gttmmadr_size(struct drm_i915_private *i915) 8529ce07d94SLucas De Marchi { 8539ce07d94SLucas De Marchi /* 8549ce07d94SLucas De Marchi * GEN6: GTTMMADR size is 4MB and GTTADR starts at 2MB offset 8559ce07d94SLucas De Marchi * GEN8: GTTMMADR size is 16MB and GTTADR starts at 8MB offset 8569ce07d94SLucas De Marchi */ 8579ce07d94SLucas De Marchi GEM_BUG_ON(GRAPHICS_VER(i915) < 6); 8589ce07d94SLucas De Marchi return (GRAPHICS_VER(i915) < 8) ? SZ_4M : SZ_16M; 8599ce07d94SLucas De Marchi } 8609ce07d94SLucas De Marchi 8619ce07d94SLucas De Marchi static unsigned int gen6_gttadr_offset(struct drm_i915_private *i915) 8629ce07d94SLucas De Marchi { 8639ce07d94SLucas De Marchi return gen6_gttmmadr_size(i915) / 2; 8649ce07d94SLucas De Marchi } 8659ce07d94SLucas De Marchi 8669ce07d94SLucas De Marchi static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) 8679ce07d94SLucas De Marchi { 8689ce07d94SLucas De Marchi struct drm_i915_private *i915 = ggtt->vm.i915; 8699ce07d94SLucas De Marchi struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 8709ce07d94SLucas De Marchi phys_addr_t phys_addr; 8719ce07d94SLucas De Marchi u32 pte_flags; 8729ce07d94SLucas De Marchi int ret; 8739ce07d94SLucas De Marchi 8746bba2b30SPiotr Piórkowski GEM_WARN_ON(pci_resource_len(pdev, GTTMMADR_BAR) != gen6_gttmmadr_size(i915)); 8756bba2b30SPiotr Piórkowski phys_addr = pci_resource_start(pdev, GTTMMADR_BAR) + gen6_gttadr_offset(i915); 8769ce07d94SLucas De Marchi 8779ce07d94SLucas De Marchi /* 8789ce07d94SLucas De Marchi * On BXT+/ICL+ writes larger than 64 bit to the GTT pagetable range 8799ce07d94SLucas De Marchi * will be dropped. For WC mappings in general we have 64 byte burst 8809ce07d94SLucas De Marchi * writes when the WC buffer is flushed, so we can't use it, but have to 8819ce07d94SLucas De Marchi * resort to an uncached mapping. The WC issue is easily caught by the 8829ce07d94SLucas De Marchi * readback check when writing GTT PTE entries. 8839ce07d94SLucas De Marchi */ 8849ce07d94SLucas De Marchi if (IS_GEN9_LP(i915) || GRAPHICS_VER(i915) >= 11) 8859ce07d94SLucas De Marchi ggtt->gsm = ioremap(phys_addr, size); 8869ce07d94SLucas De Marchi else 8879ce07d94SLucas De Marchi ggtt->gsm = ioremap_wc(phys_addr, size); 8889ce07d94SLucas De Marchi if (!ggtt->gsm) { 8899ce07d94SLucas De Marchi drm_err(&i915->drm, "Failed to map the ggtt page table\n"); 8909ce07d94SLucas De Marchi return -ENOMEM; 8919ce07d94SLucas De Marchi } 8929ce07d94SLucas De Marchi 8939ce07d94SLucas De Marchi kref_init(&ggtt->vm.resv_ref); 8949ce07d94SLucas De Marchi ret = setup_scratch_page(&ggtt->vm); 8959ce07d94SLucas De Marchi if (ret) { 8969ce07d94SLucas De Marchi drm_err(&i915->drm, "Scratch setup failed\n"); 8979ce07d94SLucas De Marchi /* iounmap will also get called at remove, but meh */ 8989ce07d94SLucas De Marchi iounmap(ggtt->gsm); 8999ce07d94SLucas De Marchi return ret; 9009ce07d94SLucas De Marchi } 9019ce07d94SLucas De Marchi 9029ce07d94SLucas De Marchi pte_flags = 0; 9039ce07d94SLucas De Marchi if (i915_gem_object_is_lmem(ggtt->vm.scratch[0])) 9049ce07d94SLucas De Marchi pte_flags |= PTE_LM; 9059ce07d94SLucas De Marchi 9069ce07d94SLucas De Marchi ggtt->vm.scratch[0]->encode = 9079ce07d94SLucas De Marchi ggtt->vm.pte_encode(px_dma(ggtt->vm.scratch[0]), 9089ce07d94SLucas De Marchi I915_CACHE_NONE, pte_flags); 9099ce07d94SLucas De Marchi 9109ce07d94SLucas De Marchi return 0; 9119ce07d94SLucas De Marchi } 9129ce07d94SLucas De Marchi 9139ce07d94SLucas De Marchi static void gen6_gmch_remove(struct i915_address_space *vm) 9149ce07d94SLucas De Marchi { 9159ce07d94SLucas De Marchi struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 9169ce07d94SLucas De Marchi 9179ce07d94SLucas De Marchi iounmap(ggtt->gsm); 9189ce07d94SLucas De Marchi free_scratch(vm); 9199ce07d94SLucas De Marchi } 9209ce07d94SLucas De Marchi 9219ce07d94SLucas De Marchi static struct resource pci_resource(struct pci_dev *pdev, int bar) 9222c86e55dSMatthew Auld { 9232c86e55dSMatthew Auld return (struct resource)DEFINE_RES_MEM(pci_resource_start(pdev, bar), 9242c86e55dSMatthew Auld pci_resource_len(pdev, bar)); 9252c86e55dSMatthew Auld } 9262c86e55dSMatthew Auld 9279ce07d94SLucas De Marchi static int gen8_gmch_probe(struct i915_ggtt *ggtt) 9289ce07d94SLucas De Marchi { 9299ce07d94SLucas De Marchi struct drm_i915_private *i915 = ggtt->vm.i915; 9309ce07d94SLucas De Marchi struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 9319ce07d94SLucas De Marchi unsigned int size; 9329ce07d94SLucas De Marchi u16 snb_gmch_ctl; 9339ce07d94SLucas De Marchi 934dbb2ffbfSAravind Iddamsetty if (!HAS_LMEM(i915) && !HAS_BAR2_SMEM_STOLEN(i915)) { 9351bba7323SPiotr Piórkowski if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR)) 9361bba7323SPiotr Piórkowski return -ENXIO; 9371bba7323SPiotr Piórkowski 9386bba2b30SPiotr Piórkowski ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR); 9399ce07d94SLucas De Marchi ggtt->mappable_end = resource_size(&ggtt->gmadr); 9409ce07d94SLucas De Marchi } 9419ce07d94SLucas De Marchi 9429ce07d94SLucas De Marchi pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); 9439ce07d94SLucas De Marchi if (IS_CHERRYVIEW(i915)) 9449ce07d94SLucas De Marchi size = chv_get_total_gtt_size(snb_gmch_ctl); 9459ce07d94SLucas De Marchi else 9469ce07d94SLucas De Marchi size = gen8_get_total_gtt_size(snb_gmch_ctl); 9479ce07d94SLucas De Marchi 9489ce07d94SLucas De Marchi ggtt->vm.alloc_pt_dma = alloc_pt_dma; 9499ce07d94SLucas De Marchi ggtt->vm.alloc_scratch_dma = alloc_pt_dma; 9509ce07d94SLucas De Marchi ggtt->vm.lmem_pt_obj_flags = I915_BO_ALLOC_PM_EARLY; 9519ce07d94SLucas De Marchi 9529ce07d94SLucas De Marchi ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; 9539ce07d94SLucas De Marchi ggtt->vm.cleanup = gen6_gmch_remove; 9549ce07d94SLucas De Marchi ggtt->vm.insert_page = gen8_ggtt_insert_page; 9559ce07d94SLucas De Marchi ggtt->vm.clear_range = nop_clear_range; 9569ce07d94SLucas De Marchi if (intel_scanout_needs_vtd_wa(i915)) 9579ce07d94SLucas De Marchi ggtt->vm.clear_range = gen8_ggtt_clear_range; 9589ce07d94SLucas De Marchi 9599ce07d94SLucas De Marchi ggtt->vm.insert_entries = gen8_ggtt_insert_entries; 9609ce07d94SLucas De Marchi 9619ce07d94SLucas De Marchi /* 9629ce07d94SLucas De Marchi * Serialize GTT updates with aperture access on BXT if VT-d is on, 9639ce07d94SLucas De Marchi * and always on CHV. 9649ce07d94SLucas De Marchi */ 9659ce07d94SLucas De Marchi if (intel_vm_no_concurrent_access_wa(i915)) { 9669ce07d94SLucas De Marchi ggtt->vm.insert_entries = bxt_vtd_ggtt_insert_entries__BKL; 9679ce07d94SLucas De Marchi ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL; 968a0696856SNirmoy Das 969a0696856SNirmoy Das /* 970a0696856SNirmoy Das * Calling stop_machine() version of GGTT update function 971a0696856SNirmoy Das * at error capture/reset path will raise lockdep warning. 972a0696856SNirmoy Das * Allow calling gen8_ggtt_insert_* directly at reset path 973a0696856SNirmoy Das * which is safe from parallel GGTT updates. 974a0696856SNirmoy Das */ 975a0696856SNirmoy Das ggtt->vm.raw_insert_page = gen8_ggtt_insert_page; 976a0696856SNirmoy Das ggtt->vm.raw_insert_entries = gen8_ggtt_insert_entries; 977a0696856SNirmoy Das 9789ce07d94SLucas De Marchi ggtt->vm.bind_async_flags = 9799ce07d94SLucas De Marchi I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND; 9809ce07d94SLucas De Marchi } 9819ce07d94SLucas De Marchi 9829ce07d94SLucas De Marchi ggtt->invalidate = gen8_ggtt_invalidate; 9839ce07d94SLucas De Marchi 9849ce07d94SLucas De Marchi ggtt->vm.vma_ops.bind_vma = intel_ggtt_bind_vma; 9859ce07d94SLucas De Marchi ggtt->vm.vma_ops.unbind_vma = intel_ggtt_unbind_vma; 9869ce07d94SLucas De Marchi 9879ce07d94SLucas De Marchi ggtt->vm.pte_encode = gen8_ggtt_pte_encode; 9889ce07d94SLucas De Marchi 9899ce07d94SLucas De Marchi setup_private_pat(ggtt->vm.gt->uncore); 9909ce07d94SLucas De Marchi 9919ce07d94SLucas De Marchi return ggtt_probe_common(ggtt, size); 9929ce07d94SLucas De Marchi } 9939ce07d94SLucas De Marchi 9949ce07d94SLucas De Marchi static u64 snb_pte_encode(dma_addr_t addr, 9959ce07d94SLucas De Marchi enum i915_cache_level level, 9969ce07d94SLucas De Marchi u32 flags) 9979ce07d94SLucas De Marchi { 9989ce07d94SLucas De Marchi gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9999ce07d94SLucas De Marchi 10009ce07d94SLucas De Marchi switch (level) { 10019ce07d94SLucas De Marchi case I915_CACHE_L3_LLC: 10029ce07d94SLucas De Marchi case I915_CACHE_LLC: 10039ce07d94SLucas De Marchi pte |= GEN6_PTE_CACHE_LLC; 10049ce07d94SLucas De Marchi break; 10059ce07d94SLucas De Marchi case I915_CACHE_NONE: 10069ce07d94SLucas De Marchi pte |= GEN6_PTE_UNCACHED; 10079ce07d94SLucas De Marchi break; 10089ce07d94SLucas De Marchi default: 10099ce07d94SLucas De Marchi MISSING_CASE(level); 10109ce07d94SLucas De Marchi } 10119ce07d94SLucas De Marchi 10129ce07d94SLucas De Marchi return pte; 10139ce07d94SLucas De Marchi } 10149ce07d94SLucas De Marchi 10159ce07d94SLucas De Marchi static u64 ivb_pte_encode(dma_addr_t addr, 10169ce07d94SLucas De Marchi enum i915_cache_level level, 10179ce07d94SLucas De Marchi u32 flags) 10189ce07d94SLucas De Marchi { 10199ce07d94SLucas De Marchi gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10209ce07d94SLucas De Marchi 10219ce07d94SLucas De Marchi switch (level) { 10229ce07d94SLucas De Marchi case I915_CACHE_L3_LLC: 10239ce07d94SLucas De Marchi pte |= GEN7_PTE_CACHE_L3_LLC; 10249ce07d94SLucas De Marchi break; 10259ce07d94SLucas De Marchi case I915_CACHE_LLC: 10269ce07d94SLucas De Marchi pte |= GEN6_PTE_CACHE_LLC; 10279ce07d94SLucas De Marchi break; 10289ce07d94SLucas De Marchi case I915_CACHE_NONE: 10299ce07d94SLucas De Marchi pte |= GEN6_PTE_UNCACHED; 10309ce07d94SLucas De Marchi break; 10319ce07d94SLucas De Marchi default: 10329ce07d94SLucas De Marchi MISSING_CASE(level); 10339ce07d94SLucas De Marchi } 10349ce07d94SLucas De Marchi 10359ce07d94SLucas De Marchi return pte; 10369ce07d94SLucas De Marchi } 10379ce07d94SLucas De Marchi 10389ce07d94SLucas De Marchi static u64 byt_pte_encode(dma_addr_t addr, 10399ce07d94SLucas De Marchi enum i915_cache_level level, 10409ce07d94SLucas De Marchi u32 flags) 10419ce07d94SLucas De Marchi { 10429ce07d94SLucas De Marchi gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10439ce07d94SLucas De Marchi 10449ce07d94SLucas De Marchi if (!(flags & PTE_READ_ONLY)) 10459ce07d94SLucas De Marchi pte |= BYT_PTE_WRITEABLE; 10469ce07d94SLucas De Marchi 10479ce07d94SLucas De Marchi if (level != I915_CACHE_NONE) 10489ce07d94SLucas De Marchi pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES; 10499ce07d94SLucas De Marchi 10509ce07d94SLucas De Marchi return pte; 10519ce07d94SLucas De Marchi } 10529ce07d94SLucas De Marchi 10539ce07d94SLucas De Marchi static u64 hsw_pte_encode(dma_addr_t addr, 10549ce07d94SLucas De Marchi enum i915_cache_level level, 10559ce07d94SLucas De Marchi u32 flags) 10569ce07d94SLucas De Marchi { 10579ce07d94SLucas De Marchi gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10589ce07d94SLucas De Marchi 10599ce07d94SLucas De Marchi if (level != I915_CACHE_NONE) 10609ce07d94SLucas De Marchi pte |= HSW_WB_LLC_AGE3; 10619ce07d94SLucas De Marchi 10629ce07d94SLucas De Marchi return pte; 10639ce07d94SLucas De Marchi } 10649ce07d94SLucas De Marchi 10659ce07d94SLucas De Marchi static u64 iris_pte_encode(dma_addr_t addr, 10669ce07d94SLucas De Marchi enum i915_cache_level level, 10679ce07d94SLucas De Marchi u32 flags) 10689ce07d94SLucas De Marchi { 10699ce07d94SLucas De Marchi gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10709ce07d94SLucas De Marchi 10719ce07d94SLucas De Marchi switch (level) { 10729ce07d94SLucas De Marchi case I915_CACHE_NONE: 10739ce07d94SLucas De Marchi break; 10749ce07d94SLucas De Marchi case I915_CACHE_WT: 10759ce07d94SLucas De Marchi pte |= HSW_WT_ELLC_LLC_AGE3; 10769ce07d94SLucas De Marchi break; 10779ce07d94SLucas De Marchi default: 10789ce07d94SLucas De Marchi pte |= HSW_WB_ELLC_LLC_AGE3; 10799ce07d94SLucas De Marchi break; 10809ce07d94SLucas De Marchi } 10819ce07d94SLucas De Marchi 10829ce07d94SLucas De Marchi return pte; 10839ce07d94SLucas De Marchi } 10849ce07d94SLucas De Marchi 10859ce07d94SLucas De Marchi static int gen6_gmch_probe(struct i915_ggtt *ggtt) 10869ce07d94SLucas De Marchi { 10879ce07d94SLucas De Marchi struct drm_i915_private *i915 = ggtt->vm.i915; 10889ce07d94SLucas De Marchi struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 10899ce07d94SLucas De Marchi unsigned int size; 10909ce07d94SLucas De Marchi u16 snb_gmch_ctl; 10919ce07d94SLucas De Marchi 10921bba7323SPiotr Piórkowski if (!i915_pci_resource_valid(pdev, GTT_APERTURE_BAR)) 10931bba7323SPiotr Piórkowski return -ENXIO; 10941bba7323SPiotr Piórkowski 10956bba2b30SPiotr Piórkowski ggtt->gmadr = pci_resource(pdev, GTT_APERTURE_BAR); 10969ce07d94SLucas De Marchi ggtt->mappable_end = resource_size(&ggtt->gmadr); 10979ce07d94SLucas De Marchi 10989ce07d94SLucas De Marchi /* 10999ce07d94SLucas De Marchi * 64/512MB is the current min/max we actually know of, but this is 11009ce07d94SLucas De Marchi * just a coarse sanity check. 11019ce07d94SLucas De Marchi */ 11029ce07d94SLucas De Marchi if (ggtt->mappable_end < (64 << 20) || 11039ce07d94SLucas De Marchi ggtt->mappable_end > (512 << 20)) { 11049ce07d94SLucas De Marchi drm_err(&i915->drm, "Unknown GMADR size (%pa)\n", 11059ce07d94SLucas De Marchi &ggtt->mappable_end); 11069ce07d94SLucas De Marchi return -ENXIO; 11079ce07d94SLucas De Marchi } 11089ce07d94SLucas De Marchi 11099ce07d94SLucas De Marchi pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); 11109ce07d94SLucas De Marchi 11119ce07d94SLucas De Marchi size = gen6_get_total_gtt_size(snb_gmch_ctl); 11129ce07d94SLucas De Marchi ggtt->vm.total = (size / sizeof(gen6_pte_t)) * I915_GTT_PAGE_SIZE; 11139ce07d94SLucas De Marchi 11149ce07d94SLucas De Marchi ggtt->vm.alloc_pt_dma = alloc_pt_dma; 11159ce07d94SLucas De Marchi ggtt->vm.alloc_scratch_dma = alloc_pt_dma; 11169ce07d94SLucas De Marchi 11179ce07d94SLucas De Marchi ggtt->vm.clear_range = nop_clear_range; 11189ce07d94SLucas De Marchi if (!HAS_FULL_PPGTT(i915) || intel_scanout_needs_vtd_wa(i915)) 11199ce07d94SLucas De Marchi ggtt->vm.clear_range = gen6_ggtt_clear_range; 11209ce07d94SLucas De Marchi ggtt->vm.insert_page = gen6_ggtt_insert_page; 11219ce07d94SLucas De Marchi ggtt->vm.insert_entries = gen6_ggtt_insert_entries; 11229ce07d94SLucas De Marchi ggtt->vm.cleanup = gen6_gmch_remove; 11239ce07d94SLucas De Marchi 11249ce07d94SLucas De Marchi ggtt->invalidate = gen6_ggtt_invalidate; 11259ce07d94SLucas De Marchi 11269ce07d94SLucas De Marchi if (HAS_EDRAM(i915)) 11279ce07d94SLucas De Marchi ggtt->vm.pte_encode = iris_pte_encode; 11289ce07d94SLucas De Marchi else if (IS_HASWELL(i915)) 11299ce07d94SLucas De Marchi ggtt->vm.pte_encode = hsw_pte_encode; 11309ce07d94SLucas De Marchi else if (IS_VALLEYVIEW(i915)) 11319ce07d94SLucas De Marchi ggtt->vm.pte_encode = byt_pte_encode; 11329ce07d94SLucas De Marchi else if (GRAPHICS_VER(i915) >= 7) 11339ce07d94SLucas De Marchi ggtt->vm.pte_encode = ivb_pte_encode; 11349ce07d94SLucas De Marchi else 11359ce07d94SLucas De Marchi ggtt->vm.pte_encode = snb_pte_encode; 11369ce07d94SLucas De Marchi 11379ce07d94SLucas De Marchi ggtt->vm.vma_ops.bind_vma = intel_ggtt_bind_vma; 11389ce07d94SLucas De Marchi ggtt->vm.vma_ops.unbind_vma = intel_ggtt_unbind_vma; 11399ce07d94SLucas De Marchi 11409ce07d94SLucas De Marchi return ggtt_probe_common(ggtt, size); 11419ce07d94SLucas De Marchi } 11429ce07d94SLucas De Marchi 11432c86e55dSMatthew Auld static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt) 11442c86e55dSMatthew Auld { 11452c86e55dSMatthew Auld struct drm_i915_private *i915 = gt->i915; 11462c86e55dSMatthew Auld int ret; 11472c86e55dSMatthew Auld 11482c86e55dSMatthew Auld ggtt->vm.gt = gt; 11492c86e55dSMatthew Auld ggtt->vm.i915 = i915; 1150e322551fSThomas Zimmermann ggtt->vm.dma = i915->drm.dev; 11514d8151aeSThomas Hellström dma_resv_init(&ggtt->vm._resv); 11522c86e55dSMatthew Auld 11539ce07d94SLucas De Marchi if (GRAPHICS_VER(i915) >= 8) 11549ce07d94SLucas De Marchi ret = gen8_gmch_probe(ggtt); 11559ce07d94SLucas De Marchi else if (GRAPHICS_VER(i915) >= 6) 11569ce07d94SLucas De Marchi ret = gen6_gmch_probe(ggtt); 11572c86e55dSMatthew Auld else 11589ce07d94SLucas De Marchi ret = intel_ggtt_gmch_probe(ggtt); 11599ce07d94SLucas De Marchi 116026ad4f8bSMaarten Lankhorst if (ret) { 11614d8151aeSThomas Hellström dma_resv_fini(&ggtt->vm._resv); 11622c86e55dSMatthew Auld return ret; 116326ad4f8bSMaarten Lankhorst } 11642c86e55dSMatthew Auld 11652c86e55dSMatthew Auld if ((ggtt->vm.total - 1) >> 32) { 116636034c95SWambui Karuga drm_err(&i915->drm, 116736034c95SWambui Karuga "We never expected a Global GTT with more than 32bits" 11682c86e55dSMatthew Auld " of address space! Found %lldM!\n", 11692c86e55dSMatthew Auld ggtt->vm.total >> 20); 11702c86e55dSMatthew Auld ggtt->vm.total = 1ULL << 32; 11712c86e55dSMatthew Auld ggtt->mappable_end = 11722c86e55dSMatthew Auld min_t(u64, ggtt->mappable_end, ggtt->vm.total); 11732c86e55dSMatthew Auld } 11742c86e55dSMatthew Auld 11752c86e55dSMatthew Auld if (ggtt->mappable_end > ggtt->vm.total) { 117636034c95SWambui Karuga drm_err(&i915->drm, 117736034c95SWambui Karuga "mappable aperture extends past end of GGTT," 11782c86e55dSMatthew Auld " aperture=%pa, total=%llx\n", 11792c86e55dSMatthew Auld &ggtt->mappable_end, ggtt->vm.total); 11802c86e55dSMatthew Auld ggtt->mappable_end = ggtt->vm.total; 11812c86e55dSMatthew Auld } 11822c86e55dSMatthew Auld 11832c86e55dSMatthew Auld /* GMADR is the PCI mmio aperture into the global GTT. */ 118436034c95SWambui Karuga drm_dbg(&i915->drm, "GGTT size = %lluM\n", ggtt->vm.total >> 20); 118536034c95SWambui Karuga drm_dbg(&i915->drm, "GMADR size = %lluM\n", 118636034c95SWambui Karuga (u64)ggtt->mappable_end >> 20); 118736034c95SWambui Karuga drm_dbg(&i915->drm, "DSM size = %lluM\n", 11882c86e55dSMatthew Auld (u64)resource_size(&intel_graphics_stolen_res) >> 20); 11892c86e55dSMatthew Auld 11902c86e55dSMatthew Auld return 0; 11912c86e55dSMatthew Auld } 11922c86e55dSMatthew Auld 11932c86e55dSMatthew Auld /** 11942c86e55dSMatthew Auld * i915_ggtt_probe_hw - Probe GGTT hardware location 11952c86e55dSMatthew Auld * @i915: i915 device 11962c86e55dSMatthew Auld */ 11972c86e55dSMatthew Auld int i915_ggtt_probe_hw(struct drm_i915_private *i915) 11982c86e55dSMatthew Auld { 11992c86e55dSMatthew Auld int ret; 12002c86e55dSMatthew Auld 1201848915c3SMichał Winiarski ret = ggtt_probe_hw(to_gt(i915)->ggtt, to_gt(i915)); 12022c86e55dSMatthew Auld if (ret) 12032c86e55dSMatthew Auld return ret; 12042c86e55dSMatthew Auld 1205a7f46d5bSTvrtko Ursulin if (i915_vtd_active(i915)) 1206dc483ba5SJani Nikula drm_info(&i915->drm, "VT-d active for gfx access\n"); 12072c86e55dSMatthew Auld 12082c86e55dSMatthew Auld return 0; 12092c86e55dSMatthew Auld } 12102c86e55dSMatthew Auld 12112c86e55dSMatthew Auld int i915_ggtt_enable_hw(struct drm_i915_private *i915) 12122c86e55dSMatthew Auld { 12139ce07d94SLucas De Marchi if (GRAPHICS_VER(i915) < 6) 12149ce07d94SLucas De Marchi return intel_ggtt_gmch_enable_hw(i915); 12159ce07d94SLucas De Marchi 12169ce07d94SLucas De Marchi return 0; 12172c86e55dSMatthew Auld } 12182c86e55dSMatthew Auld 12192c86e55dSMatthew Auld void i915_ggtt_enable_guc(struct i915_ggtt *ggtt) 12202c86e55dSMatthew Auld { 12212c86e55dSMatthew Auld GEM_BUG_ON(ggtt->invalidate != gen8_ggtt_invalidate); 12222c86e55dSMatthew Auld 12232c86e55dSMatthew Auld ggtt->invalidate = guc_ggtt_invalidate; 12242c86e55dSMatthew Auld 12252c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12262c86e55dSMatthew Auld } 12272c86e55dSMatthew Auld 12282c86e55dSMatthew Auld void i915_ggtt_disable_guc(struct i915_ggtt *ggtt) 12292c86e55dSMatthew Auld { 12302c86e55dSMatthew Auld /* XXX Temporary pardon for error unload */ 12312c86e55dSMatthew Auld if (ggtt->invalidate == gen8_ggtt_invalidate) 12322c86e55dSMatthew Auld return; 12332c86e55dSMatthew Auld 12342c86e55dSMatthew Auld /* We should only be called after i915_ggtt_enable_guc() */ 12352c86e55dSMatthew Auld GEM_BUG_ON(ggtt->invalidate != guc_ggtt_invalidate); 12362c86e55dSMatthew Auld 12372c86e55dSMatthew Auld ggtt->invalidate = gen8_ggtt_invalidate; 12382c86e55dSMatthew Auld 12392c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12402c86e55dSMatthew Auld } 12412c86e55dSMatthew Auld 12428d2f683fSImre Deak /** 12438d2f683fSImre Deak * i915_ggtt_resume_vm - Restore the memory mappings for a GGTT or DPT VM 12448d2f683fSImre Deak * @vm: The VM to restore the mappings for 12458d2f683fSImre Deak * 12468d2f683fSImre Deak * Restore the memory mappings for all objects mapped to HW via the GGTT or a 12478d2f683fSImre Deak * DPT page table. 12488d2f683fSImre Deak * 12498d2f683fSImre Deak * Returns %true if restoring the mapping for any object that was in a write 12508d2f683fSImre Deak * domain before suspend. 12518d2f683fSImre Deak */ 12528d2f683fSImre Deak bool i915_ggtt_resume_vm(struct i915_address_space *vm) 12532c86e55dSMatthew Auld { 125480e5351dSChris Wilson struct i915_vma *vma; 12558d2f683fSImre Deak bool write_domain_objs = false; 12562ef6efa7SThomas Hellström bool retained_ptes; 12572c86e55dSMatthew Auld 12588d2f683fSImre Deak drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt); 12592c86e55dSMatthew Auld 12602ef6efa7SThomas Hellström /* 12612ef6efa7SThomas Hellström * First fill our portion of the GTT with scratch pages if 12622ef6efa7SThomas Hellström * they were not retained across suspend. 12632ef6efa7SThomas Hellström */ 12642ef6efa7SThomas Hellström retained_ptes = suspend_retains_ptes(vm) && 12652ef6efa7SThomas Hellström !i915_vm_to_ggtt(vm)->pte_lost && 12662ef6efa7SThomas Hellström !GEM_WARN_ON(i915_vm_to_ggtt(vm)->probed_pte != read_last_pte(vm)); 12672ef6efa7SThomas Hellström 12682ef6efa7SThomas Hellström if (!retained_ptes) 12698d2f683fSImre Deak vm->clear_range(vm, 0, vm->total); 12702c86e55dSMatthew Auld 12712c86e55dSMatthew Auld /* clflush objects bound into the GGTT and rebind them. */ 12728d2f683fSImre Deak list_for_each_entry(vma, &vm->bound_list, vm_link) { 12732c86e55dSMatthew Auld struct drm_i915_gem_object *obj = vma->obj; 1274cd0452aaSChris Wilson unsigned int was_bound = 1275cd0452aaSChris Wilson atomic_read(&vma->flags) & I915_VMA_BIND_MASK; 12762c86e55dSMatthew Auld 1277cd0452aaSChris Wilson GEM_BUG_ON(!was_bound); 1278*bc247253SThomas Hellström if (!retained_ptes) { 1279*bc247253SThomas Hellström /* 1280*bc247253SThomas Hellström * Clear the bound flags of the vma resource to allow 1281*bc247253SThomas Hellström * ptes to be repopulated. 1282*bc247253SThomas Hellström */ 1283*bc247253SThomas Hellström vma->resource->bound_flags = 0; 1284647bfd26STvrtko Ursulin vma->ops->bind_vma(vm, NULL, vma->resource, 12852c86e55dSMatthew Auld obj ? obj->cache_level : 0, 1286cd0452aaSChris Wilson was_bound); 1287*bc247253SThomas Hellström } 12882c86e55dSMatthew Auld if (obj) { /* only used during resume => exclusive access */ 12898d2f683fSImre Deak write_domain_objs |= fetch_and_zero(&obj->write_domain); 12902c86e55dSMatthew Auld obj->read_domains |= I915_GEM_DOMAIN_GTT; 12912c86e55dSMatthew Auld } 12922c86e55dSMatthew Auld } 12932c86e55dSMatthew Auld 12948d2f683fSImre Deak return write_domain_objs; 12958d2f683fSImre Deak } 12968d2f683fSImre Deak 12978d2f683fSImre Deak void i915_ggtt_resume(struct i915_ggtt *ggtt) 12988d2f683fSImre Deak { 12998d2f683fSImre Deak bool flush; 13008d2f683fSImre Deak 13018d2f683fSImre Deak intel_gt_check_and_clear_faults(ggtt->vm.gt); 13028d2f683fSImre Deak 13038d2f683fSImre Deak flush = i915_ggtt_resume_vm(&ggtt->vm); 13048d2f683fSImre Deak 13052c86e55dSMatthew Auld ggtt->invalidate(ggtt); 13062c86e55dSMatthew Auld 13072c86e55dSMatthew Auld if (flush) 13082c86e55dSMatthew Auld wbinvd_on_all_cpus(); 13092c86e55dSMatthew Auld 1310c816723bSLucas De Marchi if (GRAPHICS_VER(ggtt->vm.i915) >= 8) 13112c86e55dSMatthew Auld setup_private_pat(ggtt->vm.gt->uncore); 1312dec9cf9eSChris Wilson 1313dec9cf9eSChris Wilson intel_ggtt_restore_fences(ggtt); 13142c86e55dSMatthew Auld } 13152ef6efa7SThomas Hellström 13162ef6efa7SThomas Hellström void i915_ggtt_mark_pte_lost(struct drm_i915_private *i915, bool val) 13172ef6efa7SThomas Hellström { 13182ef6efa7SThomas Hellström to_gt(i915)->ggtt->pte_lost = val; 13192ef6efa7SThomas Hellström } 1320