12c86e55dSMatthew Auld // SPDX-License-Identifier: MIT 22c86e55dSMatthew Auld /* 32c86e55dSMatthew Auld * Copyright © 2020 Intel Corporation 42c86e55dSMatthew Auld */ 52c86e55dSMatthew Auld 62c86e55dSMatthew Auld #include <linux/stop_machine.h> 72c86e55dSMatthew Auld 82c86e55dSMatthew Auld #include <asm/set_memory.h> 98801eb48SChen Zhou #include <asm/smp.h> 102c86e55dSMatthew Auld 1183d2bdb6SJani Nikula #include <drm/i915_drm.h> 1283d2bdb6SJani Nikula 13e762bdf5SMatthew Auld #include "gem/i915_gem_lmem.h" 14e762bdf5SMatthew Auld 152c86e55dSMatthew Auld #include "intel_gt.h" 162c86e55dSMatthew Auld #include "i915_drv.h" 172c86e55dSMatthew Auld #include "i915_scatterlist.h" 182c86e55dSMatthew Auld #include "i915_vgpu.h" 192c86e55dSMatthew Auld 202c86e55dSMatthew Auld #include "intel_gtt.h" 2133e7a975SVille Syrjälä #include "gen8_ppgtt.h" 222c86e55dSMatthew Auld 232c86e55dSMatthew Auld static int 242c86e55dSMatthew Auld i915_get_ggtt_vma_pages(struct i915_vma *vma); 252c86e55dSMatthew Auld 262c86e55dSMatthew Auld static void i915_ggtt_color_adjust(const struct drm_mm_node *node, 272c86e55dSMatthew Auld unsigned long color, 282c86e55dSMatthew Auld u64 *start, 292c86e55dSMatthew Auld u64 *end) 302c86e55dSMatthew Auld { 312c86e55dSMatthew Auld if (i915_node_color_differs(node, color)) 322c86e55dSMatthew Auld *start += I915_GTT_PAGE_SIZE; 332c86e55dSMatthew Auld 342c86e55dSMatthew Auld /* 352c86e55dSMatthew Auld * Also leave a space between the unallocated reserved node after the 362c86e55dSMatthew Auld * GTT and any objects within the GTT, i.e. we use the color adjustment 372c86e55dSMatthew Auld * to insert a guard page to prevent prefetches crossing over the 382c86e55dSMatthew Auld * GTT boundary. 392c86e55dSMatthew Auld */ 402c86e55dSMatthew Auld node = list_next_entry(node, node_list); 412c86e55dSMatthew Auld if (node->color != color) 422c86e55dSMatthew Auld *end -= I915_GTT_PAGE_SIZE; 432c86e55dSMatthew Auld } 442c86e55dSMatthew Auld 452c86e55dSMatthew Auld static int ggtt_init_hw(struct i915_ggtt *ggtt) 462c86e55dSMatthew Auld { 472c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 482c86e55dSMatthew Auld 492c86e55dSMatthew Auld i915_address_space_init(&ggtt->vm, VM_CLASS_GGTT); 502c86e55dSMatthew Auld 512c86e55dSMatthew Auld ggtt->vm.is_ggtt = true; 522c86e55dSMatthew Auld 532c86e55dSMatthew Auld /* Only VLV supports read-only GGTT mappings */ 542c86e55dSMatthew Auld ggtt->vm.has_read_only = IS_VALLEYVIEW(i915); 552c86e55dSMatthew Auld 562c86e55dSMatthew Auld if (!HAS_LLC(i915) && !HAS_PPGTT(i915)) 572c86e55dSMatthew Auld ggtt->vm.mm.color_adjust = i915_ggtt_color_adjust; 582c86e55dSMatthew Auld 592c86e55dSMatthew Auld if (ggtt->mappable_end) { 602c86e55dSMatthew Auld if (!io_mapping_init_wc(&ggtt->iomap, 612c86e55dSMatthew Auld ggtt->gmadr.start, 622c86e55dSMatthew Auld ggtt->mappable_end)) { 632c86e55dSMatthew Auld ggtt->vm.cleanup(&ggtt->vm); 642c86e55dSMatthew Auld return -EIO; 652c86e55dSMatthew Auld } 662c86e55dSMatthew Auld 672c86e55dSMatthew Auld ggtt->mtrr = arch_phys_wc_add(ggtt->gmadr.start, 682c86e55dSMatthew Auld ggtt->mappable_end); 692c86e55dSMatthew Auld } 702c86e55dSMatthew Auld 71f899f786SChris Wilson intel_ggtt_init_fences(ggtt); 722c86e55dSMatthew Auld 732c86e55dSMatthew Auld return 0; 742c86e55dSMatthew Auld } 752c86e55dSMatthew Auld 762c86e55dSMatthew Auld /** 772c86e55dSMatthew Auld * i915_ggtt_init_hw - Initialize GGTT hardware 782c86e55dSMatthew Auld * @i915: i915 device 792c86e55dSMatthew Auld */ 802c86e55dSMatthew Auld int i915_ggtt_init_hw(struct drm_i915_private *i915) 812c86e55dSMatthew Auld { 822c86e55dSMatthew Auld int ret; 832c86e55dSMatthew Auld 842c86e55dSMatthew Auld /* 852c86e55dSMatthew Auld * Note that we use page colouring to enforce a guard page at the 862c86e55dSMatthew Auld * end of the address space. This is required as the CS may prefetch 872c86e55dSMatthew Auld * beyond the end of the batch buffer, across the page boundary, 882c86e55dSMatthew Auld * and beyond the end of the GTT if we do not provide a guard. 892c86e55dSMatthew Auld */ 902c86e55dSMatthew Auld ret = ggtt_init_hw(&i915->ggtt); 912c86e55dSMatthew Auld if (ret) 922c86e55dSMatthew Auld return ret; 932c86e55dSMatthew Auld 942c86e55dSMatthew Auld return 0; 952c86e55dSMatthew Auld } 962c86e55dSMatthew Auld 972c86e55dSMatthew Auld /* 981ca9b8daSChris Wilson * Certain Gen5 chipsets require idling the GPU before 992c86e55dSMatthew Auld * unmapping anything from the GTT when VT-d is enabled. 1002c86e55dSMatthew Auld */ 1012c86e55dSMatthew Auld static bool needs_idle_maps(struct drm_i915_private *i915) 1022c86e55dSMatthew Auld { 1032c86e55dSMatthew Auld /* 1042c86e55dSMatthew Auld * Query intel_iommu to see if we need the workaround. Presumably that 1052c86e55dSMatthew Auld * was loaded first. 1062c86e55dSMatthew Auld */ 10784361529SChris Wilson if (!intel_vtd_active()) 10884361529SChris Wilson return false; 10984361529SChris Wilson 110*c816723bSLucas De Marchi if (GRAPHICS_VER(i915) == 5 && IS_MOBILE(i915)) 11184361529SChris Wilson return true; 11284361529SChris Wilson 113*c816723bSLucas De Marchi if (GRAPHICS_VER(i915) == 12) 11484361529SChris Wilson return true; /* XXX DMAR fault reason 7 */ 11584361529SChris Wilson 11684361529SChris Wilson return false; 1172c86e55dSMatthew Auld } 1182c86e55dSMatthew Auld 119e986209cSChris Wilson void i915_ggtt_suspend(struct i915_ggtt *ggtt) 1202c86e55dSMatthew Auld { 121bffa18ddSChris Wilson struct i915_vma *vma, *vn; 122bffa18ddSChris Wilson int open; 123e3793468SChris Wilson 124bffa18ddSChris Wilson mutex_lock(&ggtt->vm.mutex); 125bffa18ddSChris Wilson 126bffa18ddSChris Wilson /* Skip rewriting PTE on VMA unbind. */ 127bffa18ddSChris Wilson open = atomic_xchg(&ggtt->vm.open, 0); 128bffa18ddSChris Wilson 129bffa18ddSChris Wilson list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) { 130bffa18ddSChris Wilson GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); 131e3793468SChris Wilson i915_vma_wait_for_bind(vma); 132e3793468SChris Wilson 133bffa18ddSChris Wilson if (i915_vma_is_pinned(vma)) 134bffa18ddSChris Wilson continue; 135bffa18ddSChris Wilson 136bffa18ddSChris Wilson if (!i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) { 137bffa18ddSChris Wilson __i915_vma_evict(vma); 138bffa18ddSChris Wilson drm_mm_remove_node(&vma->node); 139bffa18ddSChris Wilson } 140bffa18ddSChris Wilson } 141bffa18ddSChris Wilson 142e986209cSChris Wilson ggtt->vm.clear_range(&ggtt->vm, 0, ggtt->vm.total); 143e986209cSChris Wilson ggtt->invalidate(ggtt); 144bffa18ddSChris Wilson atomic_set(&ggtt->vm.open, open); 145bffa18ddSChris Wilson 146bffa18ddSChris Wilson mutex_unlock(&ggtt->vm.mutex); 1472c86e55dSMatthew Auld 1482c86e55dSMatthew Auld intel_gt_check_and_clear_faults(ggtt->vm.gt); 1492c86e55dSMatthew Auld } 1502c86e55dSMatthew Auld 1512c86e55dSMatthew Auld void gen6_ggtt_invalidate(struct i915_ggtt *ggtt) 1522c86e55dSMatthew Auld { 1532c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 1542c86e55dSMatthew Auld 1552c86e55dSMatthew Auld spin_lock_irq(&uncore->lock); 1562c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); 1572c86e55dSMatthew Auld intel_uncore_read_fw(uncore, GFX_FLSH_CNTL_GEN6); 1582c86e55dSMatthew Auld spin_unlock_irq(&uncore->lock); 1592c86e55dSMatthew Auld } 1602c86e55dSMatthew Auld 1612c86e55dSMatthew Auld static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) 1622c86e55dSMatthew Auld { 1632c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 1642c86e55dSMatthew Auld 1652c86e55dSMatthew Auld /* 1662c86e55dSMatthew Auld * Note that as an uncached mmio write, this will flush the 1672c86e55dSMatthew Auld * WCB of the writes into the GGTT before it triggers the invalidate. 1682c86e55dSMatthew Auld */ 1692c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); 1702c86e55dSMatthew Auld } 1712c86e55dSMatthew Auld 1722c86e55dSMatthew Auld static void guc_ggtt_invalidate(struct i915_ggtt *ggtt) 1732c86e55dSMatthew Auld { 1742c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 1752c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 1762c86e55dSMatthew Auld 1772c86e55dSMatthew Auld gen8_ggtt_invalidate(ggtt); 1782c86e55dSMatthew Auld 179*c816723bSLucas De Marchi if (GRAPHICS_VER(i915) >= 12) 1802c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GEN12_GUC_TLB_INV_CR, 1812c86e55dSMatthew Auld GEN12_GUC_TLB_INV_CR_INVALIDATE); 1822c86e55dSMatthew Auld else 1832c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE); 1842c86e55dSMatthew Auld } 1852c86e55dSMatthew Auld 1862c86e55dSMatthew Auld static void gmch_ggtt_invalidate(struct i915_ggtt *ggtt) 1872c86e55dSMatthew Auld { 1882c86e55dSMatthew Auld intel_gtt_chipset_flush(); 1892c86e55dSMatthew Auld } 1902c86e55dSMatthew Auld 19133e7a975SVille Syrjälä u64 gen8_ggtt_pte_encode(dma_addr_t addr, 19269edc390SDaniele Ceraolo Spurio enum i915_cache_level level, 19369edc390SDaniele Ceraolo Spurio u32 flags) 19469edc390SDaniele Ceraolo Spurio { 195e762bdf5SMatthew Auld gen8_pte_t pte = addr | _PAGE_PRESENT; 196e762bdf5SMatthew Auld 197e762bdf5SMatthew Auld if (flags & PTE_LM) 198e762bdf5SMatthew Auld pte |= GEN12_GGTT_PTE_LM; 199e762bdf5SMatthew Auld 200e762bdf5SMatthew Auld return pte; 20169edc390SDaniele Ceraolo Spurio } 20269edc390SDaniele Ceraolo Spurio 2032c86e55dSMatthew Auld static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) 2042c86e55dSMatthew Auld { 2052c86e55dSMatthew Auld writeq(pte, addr); 2062c86e55dSMatthew Auld } 2072c86e55dSMatthew Auld 2082c86e55dSMatthew Auld static void gen8_ggtt_insert_page(struct i915_address_space *vm, 2092c86e55dSMatthew Auld dma_addr_t addr, 2102c86e55dSMatthew Auld u64 offset, 2112c86e55dSMatthew Auld enum i915_cache_level level, 212e762bdf5SMatthew Auld u32 flags) 2132c86e55dSMatthew Auld { 2142c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2152c86e55dSMatthew Auld gen8_pte_t __iomem *pte = 2162c86e55dSMatthew Auld (gen8_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; 2172c86e55dSMatthew Auld 218e762bdf5SMatthew Auld gen8_set_pte(pte, gen8_ggtt_pte_encode(addr, level, flags)); 2192c86e55dSMatthew Auld 2202c86e55dSMatthew Auld ggtt->invalidate(ggtt); 2212c86e55dSMatthew Auld } 2222c86e55dSMatthew Auld 2232c86e55dSMatthew Auld static void gen8_ggtt_insert_entries(struct i915_address_space *vm, 2242c86e55dSMatthew Auld struct i915_vma *vma, 2252c86e55dSMatthew Auld enum i915_cache_level level, 2262c86e55dSMatthew Auld u32 flags) 2272c86e55dSMatthew Auld { 228e762bdf5SMatthew Auld const gen8_pte_t pte_encode = gen8_ggtt_pte_encode(0, level, flags); 2294d6c1859SChris Wilson struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2304d6c1859SChris Wilson gen8_pte_t __iomem *gte; 2314d6c1859SChris Wilson gen8_pte_t __iomem *end; 2324d6c1859SChris Wilson struct sgt_iter iter; 2332c86e55dSMatthew Auld dma_addr_t addr; 2342c86e55dSMatthew Auld 2352c86e55dSMatthew Auld /* 2362c86e55dSMatthew Auld * Note that we ignore PTE_READ_ONLY here. The caller must be careful 2372c86e55dSMatthew Auld * not to allow the user to override access to a read only page. 2382c86e55dSMatthew Auld */ 2392c86e55dSMatthew Auld 2404d6c1859SChris Wilson gte = (gen8_pte_t __iomem *)ggtt->gsm; 2414d6c1859SChris Wilson gte += vma->node.start / I915_GTT_PAGE_SIZE; 2424d6c1859SChris Wilson end = gte + vma->node.size / I915_GTT_PAGE_SIZE; 2434d6c1859SChris Wilson 2444d6c1859SChris Wilson for_each_sgt_daddr(addr, iter, vma->pages) 2454d6c1859SChris Wilson gen8_set_pte(gte++, pte_encode | addr); 2464d6c1859SChris Wilson GEM_BUG_ON(gte > end); 2474d6c1859SChris Wilson 2484d6c1859SChris Wilson /* Fill the allocated but "unused" space beyond the end of the buffer */ 2494d6c1859SChris Wilson while (gte < end) 25089351925SChris Wilson gen8_set_pte(gte++, vm->scratch[0]->encode); 2512c86e55dSMatthew Auld 2522c86e55dSMatthew Auld /* 2532c86e55dSMatthew Auld * We want to flush the TLBs only after we're certain all the PTE 2542c86e55dSMatthew Auld * updates have finished. 2552c86e55dSMatthew Auld */ 2562c86e55dSMatthew Auld ggtt->invalidate(ggtt); 2572c86e55dSMatthew Auld } 2582c86e55dSMatthew Auld 2592c86e55dSMatthew Auld static void gen6_ggtt_insert_page(struct i915_address_space *vm, 2602c86e55dSMatthew Auld dma_addr_t addr, 2612c86e55dSMatthew Auld u64 offset, 2622c86e55dSMatthew Auld enum i915_cache_level level, 2632c86e55dSMatthew Auld u32 flags) 2642c86e55dSMatthew Auld { 2652c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2662c86e55dSMatthew Auld gen6_pte_t __iomem *pte = 2672c86e55dSMatthew Auld (gen6_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; 2682c86e55dSMatthew Auld 2692c86e55dSMatthew Auld iowrite32(vm->pte_encode(addr, level, flags), pte); 2702c86e55dSMatthew Auld 2712c86e55dSMatthew Auld ggtt->invalidate(ggtt); 2722c86e55dSMatthew Auld } 2732c86e55dSMatthew Auld 2742c86e55dSMatthew Auld /* 2752c86e55dSMatthew Auld * Binds an object into the global gtt with the specified cache level. 2762c86e55dSMatthew Auld * The object will be accessible to the GPU via commands whose operands 2772c86e55dSMatthew Auld * reference offsets within the global GTT as well as accessible by the GPU 2782c86e55dSMatthew Auld * through the GMADR mapped BAR (i915->mm.gtt->gtt). 2792c86e55dSMatthew Auld */ 2802c86e55dSMatthew Auld static void gen6_ggtt_insert_entries(struct i915_address_space *vm, 2812c86e55dSMatthew Auld struct i915_vma *vma, 2822c86e55dSMatthew Auld enum i915_cache_level level, 2832c86e55dSMatthew Auld u32 flags) 2842c86e55dSMatthew Auld { 2852c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2864d6c1859SChris Wilson gen6_pte_t __iomem *gte; 2874d6c1859SChris Wilson gen6_pte_t __iomem *end; 2882c86e55dSMatthew Auld struct sgt_iter iter; 2892c86e55dSMatthew Auld dma_addr_t addr; 2902c86e55dSMatthew Auld 2914d6c1859SChris Wilson gte = (gen6_pte_t __iomem *)ggtt->gsm; 2924d6c1859SChris Wilson gte += vma->node.start / I915_GTT_PAGE_SIZE; 2934d6c1859SChris Wilson end = gte + vma->node.size / I915_GTT_PAGE_SIZE; 2944d6c1859SChris Wilson 2952c86e55dSMatthew Auld for_each_sgt_daddr(addr, iter, vma->pages) 2964d6c1859SChris Wilson iowrite32(vm->pte_encode(addr, level, flags), gte++); 2974d6c1859SChris Wilson GEM_BUG_ON(gte > end); 2984d6c1859SChris Wilson 2994d6c1859SChris Wilson /* Fill the allocated but "unused" space beyond the end of the buffer */ 3004d6c1859SChris Wilson while (gte < end) 30189351925SChris Wilson iowrite32(vm->scratch[0]->encode, gte++); 3022c86e55dSMatthew Auld 3032c86e55dSMatthew Auld /* 3042c86e55dSMatthew Auld * We want to flush the TLBs only after we're certain all the PTE 3052c86e55dSMatthew Auld * updates have finished. 3062c86e55dSMatthew Auld */ 3072c86e55dSMatthew Auld ggtt->invalidate(ggtt); 3082c86e55dSMatthew Auld } 3092c86e55dSMatthew Auld 3102c86e55dSMatthew Auld static void nop_clear_range(struct i915_address_space *vm, 3112c86e55dSMatthew Auld u64 start, u64 length) 3122c86e55dSMatthew Auld { 3132c86e55dSMatthew Auld } 3142c86e55dSMatthew Auld 3152c86e55dSMatthew Auld static void gen8_ggtt_clear_range(struct i915_address_space *vm, 3162c86e55dSMatthew Auld u64 start, u64 length) 3172c86e55dSMatthew Auld { 3182c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 3192c86e55dSMatthew Auld unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 3202c86e55dSMatthew Auld unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 32189351925SChris Wilson const gen8_pte_t scratch_pte = vm->scratch[0]->encode; 3222c86e55dSMatthew Auld gen8_pte_t __iomem *gtt_base = 3232c86e55dSMatthew Auld (gen8_pte_t __iomem *)ggtt->gsm + first_entry; 3242c86e55dSMatthew Auld const int max_entries = ggtt_total_entries(ggtt) - first_entry; 3252c86e55dSMatthew Auld int i; 3262c86e55dSMatthew Auld 3272c86e55dSMatthew Auld if (WARN(num_entries > max_entries, 3282c86e55dSMatthew Auld "First entry = %d; Num entries = %d (max=%d)\n", 3292c86e55dSMatthew Auld first_entry, num_entries, max_entries)) 3302c86e55dSMatthew Auld num_entries = max_entries; 3312c86e55dSMatthew Auld 3322c86e55dSMatthew Auld for (i = 0; i < num_entries; i++) 3332c86e55dSMatthew Auld gen8_set_pte(>t_base[i], scratch_pte); 3342c86e55dSMatthew Auld } 3352c86e55dSMatthew Auld 3362c86e55dSMatthew Auld static void bxt_vtd_ggtt_wa(struct i915_address_space *vm) 3372c86e55dSMatthew Auld { 3382c86e55dSMatthew Auld /* 3392c86e55dSMatthew Auld * Make sure the internal GAM fifo has been cleared of all GTT 3402c86e55dSMatthew Auld * writes before exiting stop_machine(). This guarantees that 3412c86e55dSMatthew Auld * any aperture accesses waiting to start in another process 3422c86e55dSMatthew Auld * cannot back up behind the GTT writes causing a hang. 3432c86e55dSMatthew Auld * The register can be any arbitrary GAM register. 3442c86e55dSMatthew Auld */ 3452c86e55dSMatthew Auld intel_uncore_posting_read_fw(vm->gt->uncore, GFX_FLSH_CNTL_GEN6); 3462c86e55dSMatthew Auld } 3472c86e55dSMatthew Auld 3482c86e55dSMatthew Auld struct insert_page { 3492c86e55dSMatthew Auld struct i915_address_space *vm; 3502c86e55dSMatthew Auld dma_addr_t addr; 3512c86e55dSMatthew Auld u64 offset; 3522c86e55dSMatthew Auld enum i915_cache_level level; 3532c86e55dSMatthew Auld }; 3542c86e55dSMatthew Auld 3552c86e55dSMatthew Auld static int bxt_vtd_ggtt_insert_page__cb(void *_arg) 3562c86e55dSMatthew Auld { 3572c86e55dSMatthew Auld struct insert_page *arg = _arg; 3582c86e55dSMatthew Auld 3592c86e55dSMatthew Auld gen8_ggtt_insert_page(arg->vm, arg->addr, arg->offset, arg->level, 0); 3602c86e55dSMatthew Auld bxt_vtd_ggtt_wa(arg->vm); 3612c86e55dSMatthew Auld 3622c86e55dSMatthew Auld return 0; 3632c86e55dSMatthew Auld } 3642c86e55dSMatthew Auld 3652c86e55dSMatthew Auld static void bxt_vtd_ggtt_insert_page__BKL(struct i915_address_space *vm, 3662c86e55dSMatthew Auld dma_addr_t addr, 3672c86e55dSMatthew Auld u64 offset, 3682c86e55dSMatthew Auld enum i915_cache_level level, 3692c86e55dSMatthew Auld u32 unused) 3702c86e55dSMatthew Auld { 3712c86e55dSMatthew Auld struct insert_page arg = { vm, addr, offset, level }; 3722c86e55dSMatthew Auld 3732c86e55dSMatthew Auld stop_machine(bxt_vtd_ggtt_insert_page__cb, &arg, NULL); 3742c86e55dSMatthew Auld } 3752c86e55dSMatthew Auld 3762c86e55dSMatthew Auld struct insert_entries { 3772c86e55dSMatthew Auld struct i915_address_space *vm; 3782c86e55dSMatthew Auld struct i915_vma *vma; 3792c86e55dSMatthew Auld enum i915_cache_level level; 3802c86e55dSMatthew Auld u32 flags; 3812c86e55dSMatthew Auld }; 3822c86e55dSMatthew Auld 3832c86e55dSMatthew Auld static int bxt_vtd_ggtt_insert_entries__cb(void *_arg) 3842c86e55dSMatthew Auld { 3852c86e55dSMatthew Auld struct insert_entries *arg = _arg; 3862c86e55dSMatthew Auld 3872c86e55dSMatthew Auld gen8_ggtt_insert_entries(arg->vm, arg->vma, arg->level, arg->flags); 3882c86e55dSMatthew Auld bxt_vtd_ggtt_wa(arg->vm); 3892c86e55dSMatthew Auld 3902c86e55dSMatthew Auld return 0; 3912c86e55dSMatthew Auld } 3922c86e55dSMatthew Auld 3932c86e55dSMatthew Auld static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm, 3942c86e55dSMatthew Auld struct i915_vma *vma, 3952c86e55dSMatthew Auld enum i915_cache_level level, 3962c86e55dSMatthew Auld u32 flags) 3972c86e55dSMatthew Auld { 3982c86e55dSMatthew Auld struct insert_entries arg = { vm, vma, level, flags }; 3992c86e55dSMatthew Auld 4002c86e55dSMatthew Auld stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL); 4012c86e55dSMatthew Auld } 4022c86e55dSMatthew Auld 4032c86e55dSMatthew Auld static void gen6_ggtt_clear_range(struct i915_address_space *vm, 4042c86e55dSMatthew Auld u64 start, u64 length) 4052c86e55dSMatthew Auld { 4062c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 4072c86e55dSMatthew Auld unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 4082c86e55dSMatthew Auld unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 4092c86e55dSMatthew Auld gen6_pte_t scratch_pte, __iomem *gtt_base = 4102c86e55dSMatthew Auld (gen6_pte_t __iomem *)ggtt->gsm + first_entry; 4112c86e55dSMatthew Auld const int max_entries = ggtt_total_entries(ggtt) - first_entry; 4122c86e55dSMatthew Auld int i; 4132c86e55dSMatthew Auld 4142c86e55dSMatthew Auld if (WARN(num_entries > max_entries, 4152c86e55dSMatthew Auld "First entry = %d; Num entries = %d (max=%d)\n", 4162c86e55dSMatthew Auld first_entry, num_entries, max_entries)) 4172c86e55dSMatthew Auld num_entries = max_entries; 4182c86e55dSMatthew Auld 41989351925SChris Wilson scratch_pte = vm->scratch[0]->encode; 4202c86e55dSMatthew Auld for (i = 0; i < num_entries; i++) 4212c86e55dSMatthew Auld iowrite32(scratch_pte, >t_base[i]); 4222c86e55dSMatthew Auld } 4232c86e55dSMatthew Auld 4242c86e55dSMatthew Auld static void i915_ggtt_insert_page(struct i915_address_space *vm, 4252c86e55dSMatthew Auld dma_addr_t addr, 4262c86e55dSMatthew Auld u64 offset, 4272c86e55dSMatthew Auld enum i915_cache_level cache_level, 4282c86e55dSMatthew Auld u32 unused) 4292c86e55dSMatthew Auld { 4302c86e55dSMatthew Auld unsigned int flags = (cache_level == I915_CACHE_NONE) ? 4312c86e55dSMatthew Auld AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; 4322c86e55dSMatthew Auld 4332c86e55dSMatthew Auld intel_gtt_insert_page(addr, offset >> PAGE_SHIFT, flags); 4342c86e55dSMatthew Auld } 4352c86e55dSMatthew Auld 4362c86e55dSMatthew Auld static void i915_ggtt_insert_entries(struct i915_address_space *vm, 4372c86e55dSMatthew Auld struct i915_vma *vma, 4382c86e55dSMatthew Auld enum i915_cache_level cache_level, 4392c86e55dSMatthew Auld u32 unused) 4402c86e55dSMatthew Auld { 4412c86e55dSMatthew Auld unsigned int flags = (cache_level == I915_CACHE_NONE) ? 4422c86e55dSMatthew Auld AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; 4432c86e55dSMatthew Auld 4442c86e55dSMatthew Auld intel_gtt_insert_sg_entries(vma->pages, vma->node.start >> PAGE_SHIFT, 4452c86e55dSMatthew Auld flags); 4462c86e55dSMatthew Auld } 4472c86e55dSMatthew Auld 4482c86e55dSMatthew Auld static void i915_ggtt_clear_range(struct i915_address_space *vm, 4492c86e55dSMatthew Auld u64 start, u64 length) 4502c86e55dSMatthew Auld { 4512c86e55dSMatthew Auld intel_gtt_clear_range(start >> PAGE_SHIFT, length >> PAGE_SHIFT); 4522c86e55dSMatthew Auld } 4532c86e55dSMatthew Auld 454cd0452aaSChris Wilson static void ggtt_bind_vma(struct i915_address_space *vm, 455cd0452aaSChris Wilson struct i915_vm_pt_stash *stash, 45612b07256SChris Wilson struct i915_vma *vma, 4572c86e55dSMatthew Auld enum i915_cache_level cache_level, 4582c86e55dSMatthew Auld u32 flags) 4592c86e55dSMatthew Auld { 4602c86e55dSMatthew Auld struct drm_i915_gem_object *obj = vma->obj; 4612c86e55dSMatthew Auld u32 pte_flags; 4622c86e55dSMatthew Auld 463bf0840cdSChris Wilson if (i915_vma_is_bound(vma, ~flags & I915_VMA_BIND_MASK)) 464cd0452aaSChris Wilson return; 465bf0840cdSChris Wilson 4662c86e55dSMatthew Auld /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ 4672c86e55dSMatthew Auld pte_flags = 0; 4682c86e55dSMatthew Auld if (i915_gem_object_is_readonly(obj)) 4692c86e55dSMatthew Auld pte_flags |= PTE_READ_ONLY; 470e762bdf5SMatthew Auld if (i915_gem_object_is_lmem(obj)) 471e762bdf5SMatthew Auld pte_flags |= PTE_LM; 4722c86e55dSMatthew Auld 47312b07256SChris Wilson vm->insert_entries(vm, vma, cache_level, pte_flags); 4742c86e55dSMatthew Auld vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; 4752c86e55dSMatthew Auld } 4762c86e55dSMatthew Auld 47712b07256SChris Wilson static void ggtt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma) 4782c86e55dSMatthew Auld { 47912b07256SChris Wilson vm->clear_range(vm, vma->node.start, vma->size); 4802c86e55dSMatthew Auld } 4812c86e55dSMatthew Auld 4822c86e55dSMatthew Auld static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt) 4832c86e55dSMatthew Auld { 4842c86e55dSMatthew Auld u64 size; 4852c86e55dSMatthew Auld int ret; 4862c86e55dSMatthew Auld 48734bbfde6SDaniele Ceraolo Spurio if (!intel_uc_uses_guc(&ggtt->vm.gt->uc)) 4882c86e55dSMatthew Auld return 0; 4892c86e55dSMatthew Auld 4902c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP); 4912c86e55dSMatthew Auld size = ggtt->vm.total - GUC_GGTT_TOP; 4922c86e55dSMatthew Auld 4932c86e55dSMatthew Auld ret = i915_gem_gtt_reserve(&ggtt->vm, &ggtt->uc_fw, size, 4942c86e55dSMatthew Auld GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE, 4952c86e55dSMatthew Auld PIN_NOEVICT); 4962c86e55dSMatthew Auld if (ret) 49752ce7074SWambui Karuga drm_dbg(&ggtt->vm.i915->drm, 49852ce7074SWambui Karuga "Failed to reserve top of GGTT for GuC\n"); 4992c86e55dSMatthew Auld 5002c86e55dSMatthew Auld return ret; 5012c86e55dSMatthew Auld } 5022c86e55dSMatthew Auld 5032c86e55dSMatthew Auld static void ggtt_release_guc_top(struct i915_ggtt *ggtt) 5042c86e55dSMatthew Auld { 5052c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->uc_fw)) 5062c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->uc_fw); 5072c86e55dSMatthew Auld } 5082c86e55dSMatthew Auld 5092c86e55dSMatthew Auld static void cleanup_init_ggtt(struct i915_ggtt *ggtt) 5102c86e55dSMatthew Auld { 5112c86e55dSMatthew Auld ggtt_release_guc_top(ggtt); 5122c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->error_capture)) 5132c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->error_capture); 514742379c0SChris Wilson mutex_destroy(&ggtt->error_mutex); 5152c86e55dSMatthew Auld } 5162c86e55dSMatthew Auld 5172c86e55dSMatthew Auld static int init_ggtt(struct i915_ggtt *ggtt) 5182c86e55dSMatthew Auld { 5192c86e55dSMatthew Auld /* 5202c86e55dSMatthew Auld * Let GEM Manage all of the aperture. 5212c86e55dSMatthew Auld * 5222c86e55dSMatthew Auld * However, leave one page at the end still bound to the scratch page. 5232c86e55dSMatthew Auld * There are a number of places where the hardware apparently prefetches 5242c86e55dSMatthew Auld * past the end of the object, and we've seen multiple hangs with the 5252c86e55dSMatthew Auld * GPU head pointer stuck in a batchbuffer bound at the last page of the 5262c86e55dSMatthew Auld * aperture. One page should be enough to keep any prefetching inside 5272c86e55dSMatthew Auld * of the aperture. 5282c86e55dSMatthew Auld */ 5292c86e55dSMatthew Auld unsigned long hole_start, hole_end; 5302c86e55dSMatthew Auld struct drm_mm_node *entry; 5312c86e55dSMatthew Auld int ret; 5322c86e55dSMatthew Auld 5332c86e55dSMatthew Auld /* 5342c86e55dSMatthew Auld * GuC requires all resources that we're sharing with it to be placed in 5352c86e55dSMatthew Auld * non-WOPCM memory. If GuC is not present or not in use we still need a 5362c86e55dSMatthew Auld * small bias as ring wraparound at offset 0 sometimes hangs. No idea 5372c86e55dSMatthew Auld * why. 5382c86e55dSMatthew Auld */ 5392c86e55dSMatthew Auld ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE, 5402c86e55dSMatthew Auld intel_wopcm_guc_size(&ggtt->vm.i915->wopcm)); 5412c86e55dSMatthew Auld 5422c86e55dSMatthew Auld ret = intel_vgt_balloon(ggtt); 5432c86e55dSMatthew Auld if (ret) 5442c86e55dSMatthew Auld return ret; 5452c86e55dSMatthew Auld 546742379c0SChris Wilson mutex_init(&ggtt->error_mutex); 5472c86e55dSMatthew Auld if (ggtt->mappable_end) { 548489140b5SChris Wilson /* 549489140b5SChris Wilson * Reserve a mappable slot for our lockless error capture. 550489140b5SChris Wilson * 551489140b5SChris Wilson * We strongly prefer taking address 0x0 in order to protect 552489140b5SChris Wilson * other critical buffers against accidental overwrites, 553489140b5SChris Wilson * as writing to address 0 is a very common mistake. 554489140b5SChris Wilson * 555489140b5SChris Wilson * Since 0 may already be in use by the system (e.g. the BIOS 556489140b5SChris Wilson * framebuffer), we let the reservation fail quietly and hope 557489140b5SChris Wilson * 0 remains reserved always. 558489140b5SChris Wilson * 559489140b5SChris Wilson * If we fail to reserve 0, and then fail to find any space 560489140b5SChris Wilson * for an error-capture, remain silent. We can afford not 561489140b5SChris Wilson * to reserve an error_capture node as we have fallback 562489140b5SChris Wilson * paths, and we trust that 0 will remain reserved. However, 563489140b5SChris Wilson * the only likely reason for failure to insert is a driver 564489140b5SChris Wilson * bug, which we expect to cause other failures... 565489140b5SChris Wilson */ 566489140b5SChris Wilson ggtt->error_capture.size = I915_GTT_PAGE_SIZE; 567489140b5SChris Wilson ggtt->error_capture.color = I915_COLOR_UNEVICTABLE; 568489140b5SChris Wilson if (drm_mm_reserve_node(&ggtt->vm.mm, &ggtt->error_capture)) 569489140b5SChris Wilson drm_mm_insert_node_in_range(&ggtt->vm.mm, 5702c86e55dSMatthew Auld &ggtt->error_capture, 571489140b5SChris Wilson ggtt->error_capture.size, 0, 572489140b5SChris Wilson ggtt->error_capture.color, 5732c86e55dSMatthew Auld 0, ggtt->mappable_end, 5742c86e55dSMatthew Auld DRM_MM_INSERT_LOW); 5752c86e55dSMatthew Auld } 576489140b5SChris Wilson if (drm_mm_node_allocated(&ggtt->error_capture)) 577489140b5SChris Wilson drm_dbg(&ggtt->vm.i915->drm, 578489140b5SChris Wilson "Reserved GGTT:[%llx, %llx] for use by error capture\n", 579489140b5SChris Wilson ggtt->error_capture.start, 580489140b5SChris Wilson ggtt->error_capture.start + ggtt->error_capture.size); 5812c86e55dSMatthew Auld 5822c86e55dSMatthew Auld /* 5832c86e55dSMatthew Auld * The upper portion of the GuC address space has a sizeable hole 5842c86e55dSMatthew Auld * (several MB) that is inaccessible by GuC. Reserve this range within 5852c86e55dSMatthew Auld * GGTT as it can comfortably hold GuC/HuC firmware images. 5862c86e55dSMatthew Auld */ 5872c86e55dSMatthew Auld ret = ggtt_reserve_guc_top(ggtt); 5882c86e55dSMatthew Auld if (ret) 5892c86e55dSMatthew Auld goto err; 5902c86e55dSMatthew Auld 5912c86e55dSMatthew Auld /* Clear any non-preallocated blocks */ 5922c86e55dSMatthew Auld drm_mm_for_each_hole(entry, &ggtt->vm.mm, hole_start, hole_end) { 593489140b5SChris Wilson drm_dbg(&ggtt->vm.i915->drm, 59452ce7074SWambui Karuga "clearing unused GTT space: [%lx, %lx]\n", 5952c86e55dSMatthew Auld hole_start, hole_end); 5962c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, hole_start, 5972c86e55dSMatthew Auld hole_end - hole_start); 5982c86e55dSMatthew Auld } 5992c86e55dSMatthew Auld 6002c86e55dSMatthew Auld /* And finally clear the reserved guard page */ 6012c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, ggtt->vm.total - PAGE_SIZE, PAGE_SIZE); 6022c86e55dSMatthew Auld 6032c86e55dSMatthew Auld return 0; 6042c86e55dSMatthew Auld 6052c86e55dSMatthew Auld err: 6062c86e55dSMatthew Auld cleanup_init_ggtt(ggtt); 6072c86e55dSMatthew Auld return ret; 6082c86e55dSMatthew Auld } 6092c86e55dSMatthew Auld 610cd0452aaSChris Wilson static void aliasing_gtt_bind_vma(struct i915_address_space *vm, 611cd0452aaSChris Wilson struct i915_vm_pt_stash *stash, 61212b07256SChris Wilson struct i915_vma *vma, 6132c86e55dSMatthew Auld enum i915_cache_level cache_level, 6142c86e55dSMatthew Auld u32 flags) 6152c86e55dSMatthew Auld { 6162c86e55dSMatthew Auld u32 pte_flags; 6172c86e55dSMatthew Auld 6182c86e55dSMatthew Auld /* Currently applicable only to VLV */ 6192c86e55dSMatthew Auld pte_flags = 0; 6202c86e55dSMatthew Auld if (i915_gem_object_is_readonly(vma->obj)) 6212c86e55dSMatthew Auld pte_flags |= PTE_READ_ONLY; 6222c86e55dSMatthew Auld 623cd0452aaSChris Wilson if (flags & I915_VMA_LOCAL_BIND) 624cd0452aaSChris Wilson ppgtt_bind_vma(&i915_vm_to_ggtt(vm)->alias->vm, 625cd0452aaSChris Wilson stash, vma, cache_level, flags); 6262c86e55dSMatthew Auld 627c0e60347SChris Wilson if (flags & I915_VMA_GLOBAL_BIND) 62812b07256SChris Wilson vm->insert_entries(vm, vma, cache_level, pte_flags); 6292c86e55dSMatthew Auld } 6302c86e55dSMatthew Auld 63112b07256SChris Wilson static void aliasing_gtt_unbind_vma(struct i915_address_space *vm, 63212b07256SChris Wilson struct i915_vma *vma) 6332c86e55dSMatthew Auld { 63412b07256SChris Wilson if (i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) 6352c86e55dSMatthew Auld vm->clear_range(vm, vma->node.start, vma->size); 6362c86e55dSMatthew Auld 63712b07256SChris Wilson if (i915_vma_is_bound(vma, I915_VMA_LOCAL_BIND)) 63812b07256SChris Wilson ppgtt_unbind_vma(&i915_vm_to_ggtt(vm)->alias->vm, vma); 6392c86e55dSMatthew Auld } 6402c86e55dSMatthew Auld 6412c86e55dSMatthew Auld static int init_aliasing_ppgtt(struct i915_ggtt *ggtt) 6422c86e55dSMatthew Auld { 643cd0452aaSChris Wilson struct i915_vm_pt_stash stash = {}; 6442c86e55dSMatthew Auld struct i915_ppgtt *ppgtt; 6452c86e55dSMatthew Auld int err; 6462c86e55dSMatthew Auld 6472c86e55dSMatthew Auld ppgtt = i915_ppgtt_create(ggtt->vm.gt); 6482c86e55dSMatthew Auld if (IS_ERR(ppgtt)) 6492c86e55dSMatthew Auld return PTR_ERR(ppgtt); 6502c86e55dSMatthew Auld 6512c86e55dSMatthew Auld if (GEM_WARN_ON(ppgtt->vm.total < ggtt->vm.total)) { 6522c86e55dSMatthew Auld err = -ENODEV; 6532c86e55dSMatthew Auld goto err_ppgtt; 6542c86e55dSMatthew Auld } 6552c86e55dSMatthew Auld 656cd0452aaSChris Wilson err = i915_vm_alloc_pt_stash(&ppgtt->vm, &stash, ggtt->vm.total); 657cd0452aaSChris Wilson if (err) 658cd0452aaSChris Wilson goto err_ppgtt; 659cd0452aaSChris Wilson 66026ad4f8bSMaarten Lankhorst i915_gem_object_lock(ppgtt->vm.scratch[0], NULL); 661529b9ec8SMatthew Auld err = i915_vm_map_pt_stash(&ppgtt->vm, &stash); 66226ad4f8bSMaarten Lankhorst i915_gem_object_unlock(ppgtt->vm.scratch[0]); 66389351925SChris Wilson if (err) 66489351925SChris Wilson goto err_stash; 66589351925SChris Wilson 6662c86e55dSMatthew Auld /* 6672c86e55dSMatthew Auld * Note we only pre-allocate as far as the end of the global 6682c86e55dSMatthew Auld * GTT. On 48b / 4-level page-tables, the difference is very, 6692c86e55dSMatthew Auld * very significant! We have to preallocate as GVT/vgpu does 6702c86e55dSMatthew Auld * not like the page directory disappearing. 6712c86e55dSMatthew Auld */ 672cd0452aaSChris Wilson ppgtt->vm.allocate_va_range(&ppgtt->vm, &stash, 0, ggtt->vm.total); 6732c86e55dSMatthew Auld 6742c86e55dSMatthew Auld ggtt->alias = ppgtt; 6752c86e55dSMatthew Auld ggtt->vm.bind_async_flags |= ppgtt->vm.bind_async_flags; 6762c86e55dSMatthew Auld 6772c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.vma_ops.bind_vma != ggtt_bind_vma); 6782c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = aliasing_gtt_bind_vma; 6792c86e55dSMatthew Auld 6802c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.vma_ops.unbind_vma != ggtt_unbind_vma); 6812c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = aliasing_gtt_unbind_vma; 6822c86e55dSMatthew Auld 683cd0452aaSChris Wilson i915_vm_free_pt_stash(&ppgtt->vm, &stash); 6842c86e55dSMatthew Auld return 0; 6852c86e55dSMatthew Auld 68689351925SChris Wilson err_stash: 68789351925SChris Wilson i915_vm_free_pt_stash(&ppgtt->vm, &stash); 6882c86e55dSMatthew Auld err_ppgtt: 6892c86e55dSMatthew Auld i915_vm_put(&ppgtt->vm); 6902c86e55dSMatthew Auld return err; 6912c86e55dSMatthew Auld } 6922c86e55dSMatthew Auld 6932c86e55dSMatthew Auld static void fini_aliasing_ppgtt(struct i915_ggtt *ggtt) 6942c86e55dSMatthew Auld { 6952c86e55dSMatthew Auld struct i915_ppgtt *ppgtt; 6962c86e55dSMatthew Auld 6972c86e55dSMatthew Auld ppgtt = fetch_and_zero(&ggtt->alias); 6982c86e55dSMatthew Auld if (!ppgtt) 6992c86e55dSMatthew Auld return; 7002c86e55dSMatthew Auld 7012c86e55dSMatthew Auld i915_vm_put(&ppgtt->vm); 7022c86e55dSMatthew Auld 7032c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 7042c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 7052c86e55dSMatthew Auld } 7062c86e55dSMatthew Auld 7072c86e55dSMatthew Auld int i915_init_ggtt(struct drm_i915_private *i915) 7082c86e55dSMatthew Auld { 7092c86e55dSMatthew Auld int ret; 7102c86e55dSMatthew Auld 7112c86e55dSMatthew Auld ret = init_ggtt(&i915->ggtt); 7122c86e55dSMatthew Auld if (ret) 7132c86e55dSMatthew Auld return ret; 7142c86e55dSMatthew Auld 7152c86e55dSMatthew Auld if (INTEL_PPGTT(i915) == INTEL_PPGTT_ALIASING) { 7162c86e55dSMatthew Auld ret = init_aliasing_ppgtt(&i915->ggtt); 7172c86e55dSMatthew Auld if (ret) 7182c86e55dSMatthew Auld cleanup_init_ggtt(&i915->ggtt); 7192c86e55dSMatthew Auld } 7202c86e55dSMatthew Auld 7212c86e55dSMatthew Auld return 0; 7222c86e55dSMatthew Auld } 7232c86e55dSMatthew Auld 7242c86e55dSMatthew Auld static void ggtt_cleanup_hw(struct i915_ggtt *ggtt) 7252c86e55dSMatthew Auld { 7262c86e55dSMatthew Auld struct i915_vma *vma, *vn; 7272c86e55dSMatthew Auld 7282c86e55dSMatthew Auld atomic_set(&ggtt->vm.open, 0); 7292c86e55dSMatthew Auld 7302c86e55dSMatthew Auld rcu_barrier(); /* flush the RCU'ed__i915_vm_release */ 7312c86e55dSMatthew Auld flush_workqueue(ggtt->vm.i915->wq); 7322c86e55dSMatthew Auld 7332c86e55dSMatthew Auld mutex_lock(&ggtt->vm.mutex); 7342c86e55dSMatthew Auld 7352c86e55dSMatthew Auld list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) 7362c86e55dSMatthew Auld WARN_ON(__i915_vma_unbind(vma)); 7372c86e55dSMatthew Auld 7382c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->error_capture)) 7392c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->error_capture); 740742379c0SChris Wilson mutex_destroy(&ggtt->error_mutex); 7412c86e55dSMatthew Auld 7422c86e55dSMatthew Auld ggtt_release_guc_top(ggtt); 7432c86e55dSMatthew Auld intel_vgt_deballoon(ggtt); 7442c86e55dSMatthew Auld 7452c86e55dSMatthew Auld ggtt->vm.cleanup(&ggtt->vm); 7462c86e55dSMatthew Auld 7472c86e55dSMatthew Auld mutex_unlock(&ggtt->vm.mutex); 7482c86e55dSMatthew Auld i915_address_space_fini(&ggtt->vm); 7492c86e55dSMatthew Auld 7502c86e55dSMatthew Auld arch_phys_wc_del(ggtt->mtrr); 7512c86e55dSMatthew Auld 7522c86e55dSMatthew Auld if (ggtt->iomap.size) 7532c86e55dSMatthew Auld io_mapping_fini(&ggtt->iomap); 7542c86e55dSMatthew Auld } 7552c86e55dSMatthew Auld 7562c86e55dSMatthew Auld /** 7572c86e55dSMatthew Auld * i915_ggtt_driver_release - Clean up GGTT hardware initialization 7582c86e55dSMatthew Auld * @i915: i915 device 7592c86e55dSMatthew Auld */ 7602c86e55dSMatthew Auld void i915_ggtt_driver_release(struct drm_i915_private *i915) 7612c86e55dSMatthew Auld { 7620b6bc81dSChris Wilson struct i915_ggtt *ggtt = &i915->ggtt; 7632c86e55dSMatthew Auld 7640b6bc81dSChris Wilson fini_aliasing_ppgtt(ggtt); 7652c86e55dSMatthew Auld 7660b6bc81dSChris Wilson intel_ggtt_fini_fences(ggtt); 7670b6bc81dSChris Wilson ggtt_cleanup_hw(ggtt); 7682c86e55dSMatthew Auld } 7692c86e55dSMatthew Auld 7704d8151aeSThomas Hellström /** 7714d8151aeSThomas Hellström * i915_ggtt_driver_late_release - Cleanup of GGTT that needs to be done after 7724d8151aeSThomas Hellström * all free objects have been drained. 7734d8151aeSThomas Hellström * @i915: i915 device 7744d8151aeSThomas Hellström */ 7754d8151aeSThomas Hellström void i915_ggtt_driver_late_release(struct drm_i915_private *i915) 7764d8151aeSThomas Hellström { 7774d8151aeSThomas Hellström struct i915_ggtt *ggtt = &i915->ggtt; 7784d8151aeSThomas Hellström 7794d8151aeSThomas Hellström GEM_WARN_ON(kref_read(&ggtt->vm.resv_ref) != 1); 7804d8151aeSThomas Hellström dma_resv_fini(&ggtt->vm._resv); 7814d8151aeSThomas Hellström } 7824d8151aeSThomas Hellström 7832c86e55dSMatthew Auld static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) 7842c86e55dSMatthew Auld { 7852c86e55dSMatthew Auld snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT; 7862c86e55dSMatthew Auld snb_gmch_ctl &= SNB_GMCH_GGMS_MASK; 7872c86e55dSMatthew Auld return snb_gmch_ctl << 20; 7882c86e55dSMatthew Auld } 7892c86e55dSMatthew Auld 7902c86e55dSMatthew Auld static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl) 7912c86e55dSMatthew Auld { 7922c86e55dSMatthew Auld bdw_gmch_ctl >>= BDW_GMCH_GGMS_SHIFT; 7932c86e55dSMatthew Auld bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK; 7942c86e55dSMatthew Auld if (bdw_gmch_ctl) 7952c86e55dSMatthew Auld bdw_gmch_ctl = 1 << bdw_gmch_ctl; 7962c86e55dSMatthew Auld 7972c86e55dSMatthew Auld #ifdef CONFIG_X86_32 7982c86e55dSMatthew Auld /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * I915_GTT_PAGE_SIZE */ 7992c86e55dSMatthew Auld if (bdw_gmch_ctl > 4) 8002c86e55dSMatthew Auld bdw_gmch_ctl = 4; 8012c86e55dSMatthew Auld #endif 8022c86e55dSMatthew Auld 8032c86e55dSMatthew Auld return bdw_gmch_ctl << 20; 8042c86e55dSMatthew Auld } 8052c86e55dSMatthew Auld 8062c86e55dSMatthew Auld static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl) 8072c86e55dSMatthew Auld { 8082c86e55dSMatthew Auld gmch_ctrl >>= SNB_GMCH_GGMS_SHIFT; 8092c86e55dSMatthew Auld gmch_ctrl &= SNB_GMCH_GGMS_MASK; 8102c86e55dSMatthew Auld 8112c86e55dSMatthew Auld if (gmch_ctrl) 8122c86e55dSMatthew Auld return 1 << (20 + gmch_ctrl); 8132c86e55dSMatthew Auld 8142c86e55dSMatthew Auld return 0; 8152c86e55dSMatthew Auld } 8162c86e55dSMatthew Auld 8172c86e55dSMatthew Auld static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) 8182c86e55dSMatthew Auld { 8192c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 820e322551fSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 8212c86e55dSMatthew Auld phys_addr_t phys_addr; 822e762bdf5SMatthew Auld u32 pte_flags; 8232c86e55dSMatthew Auld int ret; 8242c86e55dSMatthew Auld 8252c86e55dSMatthew Auld /* For Modern GENs the PTEs and register space are split in the BAR */ 8262c86e55dSMatthew Auld phys_addr = pci_resource_start(pdev, 0) + pci_resource_len(pdev, 0) / 2; 8272c86e55dSMatthew Auld 8282c86e55dSMatthew Auld /* 8292c86e55dSMatthew Auld * On BXT+/CNL+ writes larger than 64 bit to the GTT pagetable range 8302c86e55dSMatthew Auld * will be dropped. For WC mappings in general we have 64 byte burst 8312c86e55dSMatthew Auld * writes when the WC buffer is flushed, so we can't use it, but have to 8322c86e55dSMatthew Auld * resort to an uncached mapping. The WC issue is easily caught by the 8332c86e55dSMatthew Auld * readback check when writing GTT PTE entries. 8342c86e55dSMatthew Auld */ 835*c816723bSLucas De Marchi if (IS_GEN9_LP(i915) || GRAPHICS_VER(i915) >= 10) 8369f68e365SLinus Torvalds ggtt->gsm = ioremap(phys_addr, size); 8372c86e55dSMatthew Auld else 8382c86e55dSMatthew Auld ggtt->gsm = ioremap_wc(phys_addr, size); 8392c86e55dSMatthew Auld if (!ggtt->gsm) { 84036034c95SWambui Karuga drm_err(&i915->drm, "Failed to map the ggtt page table\n"); 8412c86e55dSMatthew Auld return -ENOMEM; 8422c86e55dSMatthew Auld } 8432c86e55dSMatthew Auld 8444d8151aeSThomas Hellström kref_init(&ggtt->vm.resv_ref); 84589351925SChris Wilson ret = setup_scratch_page(&ggtt->vm); 8462c86e55dSMatthew Auld if (ret) { 84736034c95SWambui Karuga drm_err(&i915->drm, "Scratch setup failed\n"); 8482c86e55dSMatthew Auld /* iounmap will also get called at remove, but meh */ 8492c86e55dSMatthew Auld iounmap(ggtt->gsm); 8502c86e55dSMatthew Auld return ret; 8512c86e55dSMatthew Auld } 8522c86e55dSMatthew Auld 853e762bdf5SMatthew Auld pte_flags = 0; 854e762bdf5SMatthew Auld if (i915_gem_object_is_lmem(ggtt->vm.scratch[0])) 855e762bdf5SMatthew Auld pte_flags |= PTE_LM; 856e762bdf5SMatthew Auld 85789351925SChris Wilson ggtt->vm.scratch[0]->encode = 85889351925SChris Wilson ggtt->vm.pte_encode(px_dma(ggtt->vm.scratch[0]), 859e762bdf5SMatthew Auld I915_CACHE_NONE, pte_flags); 8602c86e55dSMatthew Auld 8612c86e55dSMatthew Auld return 0; 8622c86e55dSMatthew Auld } 8632c86e55dSMatthew Auld 8642c86e55dSMatthew Auld int ggtt_set_pages(struct i915_vma *vma) 8652c86e55dSMatthew Auld { 8662c86e55dSMatthew Auld int ret; 8672c86e55dSMatthew Auld 8682c86e55dSMatthew Auld GEM_BUG_ON(vma->pages); 8692c86e55dSMatthew Auld 8702c86e55dSMatthew Auld ret = i915_get_ggtt_vma_pages(vma); 8712c86e55dSMatthew Auld if (ret) 8722c86e55dSMatthew Auld return ret; 8732c86e55dSMatthew Auld 8742c86e55dSMatthew Auld vma->page_sizes = vma->obj->mm.page_sizes; 8752c86e55dSMatthew Auld 8762c86e55dSMatthew Auld return 0; 8772c86e55dSMatthew Auld } 8782c86e55dSMatthew Auld 8792c86e55dSMatthew Auld static void gen6_gmch_remove(struct i915_address_space *vm) 8802c86e55dSMatthew Auld { 8812c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 8822c86e55dSMatthew Auld 8832c86e55dSMatthew Auld iounmap(ggtt->gsm); 88489351925SChris Wilson free_scratch(vm); 8852c86e55dSMatthew Auld } 8862c86e55dSMatthew Auld 8872c86e55dSMatthew Auld static struct resource pci_resource(struct pci_dev *pdev, int bar) 8882c86e55dSMatthew Auld { 8892c86e55dSMatthew Auld return (struct resource)DEFINE_RES_MEM(pci_resource_start(pdev, bar), 8902c86e55dSMatthew Auld pci_resource_len(pdev, bar)); 8912c86e55dSMatthew Auld } 8922c86e55dSMatthew Auld 8932c86e55dSMatthew Auld static int gen8_gmch_probe(struct i915_ggtt *ggtt) 8942c86e55dSMatthew Auld { 8952c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 896e322551fSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 8972c86e55dSMatthew Auld unsigned int size; 8982c86e55dSMatthew Auld u16 snb_gmch_ctl; 8992c86e55dSMatthew Auld 9002c86e55dSMatthew Auld /* TODO: We're not aware of mappable constraints on gen8 yet */ 901b1e93a85SLucas De Marchi if (!HAS_LMEM(i915)) { 9022c86e55dSMatthew Auld ggtt->gmadr = pci_resource(pdev, 2); 9032c86e55dSMatthew Auld ggtt->mappable_end = resource_size(&ggtt->gmadr); 9042c86e55dSMatthew Auld } 9052c86e55dSMatthew Auld 9062c86e55dSMatthew Auld pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); 9072c86e55dSMatthew Auld if (IS_CHERRYVIEW(i915)) 9082c86e55dSMatthew Auld size = chv_get_total_gtt_size(snb_gmch_ctl); 9092c86e55dSMatthew Auld else 9102c86e55dSMatthew Auld size = gen8_get_total_gtt_size(snb_gmch_ctl); 9112c86e55dSMatthew Auld 91289351925SChris Wilson ggtt->vm.alloc_pt_dma = alloc_pt_dma; 91389351925SChris Wilson 9142c86e55dSMatthew Auld ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; 9152c86e55dSMatthew Auld ggtt->vm.cleanup = gen6_gmch_remove; 9162c86e55dSMatthew Auld ggtt->vm.insert_page = gen8_ggtt_insert_page; 9172c86e55dSMatthew Auld ggtt->vm.clear_range = nop_clear_range; 9182c86e55dSMatthew Auld if (intel_scanout_needs_vtd_wa(i915)) 9192c86e55dSMatthew Auld ggtt->vm.clear_range = gen8_ggtt_clear_range; 9202c86e55dSMatthew Auld 9212c86e55dSMatthew Auld ggtt->vm.insert_entries = gen8_ggtt_insert_entries; 9222c86e55dSMatthew Auld 923bc6f80ccSMaarten Lankhorst /* 924bc6f80ccSMaarten Lankhorst * Serialize GTT updates with aperture access on BXT if VT-d is on, 925bc6f80ccSMaarten Lankhorst * and always on CHV. 926bc6f80ccSMaarten Lankhorst */ 927bc6f80ccSMaarten Lankhorst if (intel_vm_no_concurrent_access_wa(i915)) { 9282c86e55dSMatthew Auld ggtt->vm.insert_entries = bxt_vtd_ggtt_insert_entries__BKL; 9292c86e55dSMatthew Auld ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL; 930a34f61d2SChris Wilson ggtt->vm.bind_async_flags = 931a34f61d2SChris Wilson I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND; 9322c86e55dSMatthew Auld } 9332c86e55dSMatthew Auld 9342c86e55dSMatthew Auld ggtt->invalidate = gen8_ggtt_invalidate; 9352c86e55dSMatthew Auld 9362c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 9372c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 9382c86e55dSMatthew Auld ggtt->vm.vma_ops.set_pages = ggtt_set_pages; 9392c86e55dSMatthew Auld ggtt->vm.vma_ops.clear_pages = clear_pages; 9402c86e55dSMatthew Auld 94169edc390SDaniele Ceraolo Spurio ggtt->vm.pte_encode = gen8_ggtt_pte_encode; 9422c86e55dSMatthew Auld 9432c86e55dSMatthew Auld setup_private_pat(ggtt->vm.gt->uncore); 9442c86e55dSMatthew Auld 9452c86e55dSMatthew Auld return ggtt_probe_common(ggtt, size); 9462c86e55dSMatthew Auld } 9472c86e55dSMatthew Auld 9482c86e55dSMatthew Auld static u64 snb_pte_encode(dma_addr_t addr, 9492c86e55dSMatthew Auld enum i915_cache_level level, 9502c86e55dSMatthew Auld u32 flags) 9512c86e55dSMatthew Auld { 9522c86e55dSMatthew Auld gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9532c86e55dSMatthew Auld 9542c86e55dSMatthew Auld switch (level) { 9552c86e55dSMatthew Auld case I915_CACHE_L3_LLC: 9562c86e55dSMatthew Auld case I915_CACHE_LLC: 9572c86e55dSMatthew Auld pte |= GEN6_PTE_CACHE_LLC; 9582c86e55dSMatthew Auld break; 9592c86e55dSMatthew Auld case I915_CACHE_NONE: 9602c86e55dSMatthew Auld pte |= GEN6_PTE_UNCACHED; 9612c86e55dSMatthew Auld break; 9622c86e55dSMatthew Auld default: 9632c86e55dSMatthew Auld MISSING_CASE(level); 9642c86e55dSMatthew Auld } 9652c86e55dSMatthew Auld 9662c86e55dSMatthew Auld return pte; 9672c86e55dSMatthew Auld } 9682c86e55dSMatthew Auld 9692c86e55dSMatthew Auld static u64 ivb_pte_encode(dma_addr_t addr, 9702c86e55dSMatthew Auld enum i915_cache_level level, 9712c86e55dSMatthew Auld u32 flags) 9722c86e55dSMatthew Auld { 9732c86e55dSMatthew Auld gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9742c86e55dSMatthew Auld 9752c86e55dSMatthew Auld switch (level) { 9762c86e55dSMatthew Auld case I915_CACHE_L3_LLC: 9772c86e55dSMatthew Auld pte |= GEN7_PTE_CACHE_L3_LLC; 9782c86e55dSMatthew Auld break; 9792c86e55dSMatthew Auld case I915_CACHE_LLC: 9802c86e55dSMatthew Auld pte |= GEN6_PTE_CACHE_LLC; 9812c86e55dSMatthew Auld break; 9822c86e55dSMatthew Auld case I915_CACHE_NONE: 9832c86e55dSMatthew Auld pte |= GEN6_PTE_UNCACHED; 9842c86e55dSMatthew Auld break; 9852c86e55dSMatthew Auld default: 9862c86e55dSMatthew Auld MISSING_CASE(level); 9872c86e55dSMatthew Auld } 9882c86e55dSMatthew Auld 9892c86e55dSMatthew Auld return pte; 9902c86e55dSMatthew Auld } 9912c86e55dSMatthew Auld 9922c86e55dSMatthew Auld static u64 byt_pte_encode(dma_addr_t addr, 9932c86e55dSMatthew Auld enum i915_cache_level level, 9942c86e55dSMatthew Auld u32 flags) 9952c86e55dSMatthew Auld { 9962c86e55dSMatthew Auld gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9972c86e55dSMatthew Auld 9982c86e55dSMatthew Auld if (!(flags & PTE_READ_ONLY)) 9992c86e55dSMatthew Auld pte |= BYT_PTE_WRITEABLE; 10002c86e55dSMatthew Auld 10012c86e55dSMatthew Auld if (level != I915_CACHE_NONE) 10022c86e55dSMatthew Auld pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES; 10032c86e55dSMatthew Auld 10042c86e55dSMatthew Auld return pte; 10052c86e55dSMatthew Auld } 10062c86e55dSMatthew Auld 10072c86e55dSMatthew Auld static u64 hsw_pte_encode(dma_addr_t addr, 10082c86e55dSMatthew Auld enum i915_cache_level level, 10092c86e55dSMatthew Auld u32 flags) 10102c86e55dSMatthew Auld { 10112c86e55dSMatthew Auld gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10122c86e55dSMatthew Auld 10132c86e55dSMatthew Auld if (level != I915_CACHE_NONE) 10142c86e55dSMatthew Auld pte |= HSW_WB_LLC_AGE3; 10152c86e55dSMatthew Auld 10162c86e55dSMatthew Auld return pte; 10172c86e55dSMatthew Auld } 10182c86e55dSMatthew Auld 10192c86e55dSMatthew Auld static u64 iris_pte_encode(dma_addr_t addr, 10202c86e55dSMatthew Auld enum i915_cache_level level, 10212c86e55dSMatthew Auld u32 flags) 10222c86e55dSMatthew Auld { 10232c86e55dSMatthew Auld gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10242c86e55dSMatthew Auld 10252c86e55dSMatthew Auld switch (level) { 10262c86e55dSMatthew Auld case I915_CACHE_NONE: 10272c86e55dSMatthew Auld break; 10282c86e55dSMatthew Auld case I915_CACHE_WT: 10292c86e55dSMatthew Auld pte |= HSW_WT_ELLC_LLC_AGE3; 10302c86e55dSMatthew Auld break; 10312c86e55dSMatthew Auld default: 10322c86e55dSMatthew Auld pte |= HSW_WB_ELLC_LLC_AGE3; 10332c86e55dSMatthew Auld break; 10342c86e55dSMatthew Auld } 10352c86e55dSMatthew Auld 10362c86e55dSMatthew Auld return pte; 10372c86e55dSMatthew Auld } 10382c86e55dSMatthew Auld 10392c86e55dSMatthew Auld static int gen6_gmch_probe(struct i915_ggtt *ggtt) 10402c86e55dSMatthew Auld { 10412c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 1042e322551fSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 10432c86e55dSMatthew Auld unsigned int size; 10442c86e55dSMatthew Auld u16 snb_gmch_ctl; 10452c86e55dSMatthew Auld 10462c86e55dSMatthew Auld ggtt->gmadr = pci_resource(pdev, 2); 10472c86e55dSMatthew Auld ggtt->mappable_end = resource_size(&ggtt->gmadr); 10482c86e55dSMatthew Auld 10492c86e55dSMatthew Auld /* 10502c86e55dSMatthew Auld * 64/512MB is the current min/max we actually know of, but this is 10512c86e55dSMatthew Auld * just a coarse sanity check. 10522c86e55dSMatthew Auld */ 10532c86e55dSMatthew Auld if (ggtt->mappable_end < (64<<20) || ggtt->mappable_end > (512<<20)) { 105436034c95SWambui Karuga drm_err(&i915->drm, "Unknown GMADR size (%pa)\n", 105536034c95SWambui Karuga &ggtt->mappable_end); 10562c86e55dSMatthew Auld return -ENXIO; 10572c86e55dSMatthew Auld } 10582c86e55dSMatthew Auld 10592c86e55dSMatthew Auld pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); 10602c86e55dSMatthew Auld 10612c86e55dSMatthew Auld size = gen6_get_total_gtt_size(snb_gmch_ctl); 10622c86e55dSMatthew Auld ggtt->vm.total = (size / sizeof(gen6_pte_t)) * I915_GTT_PAGE_SIZE; 10632c86e55dSMatthew Auld 106489351925SChris Wilson ggtt->vm.alloc_pt_dma = alloc_pt_dma; 106589351925SChris Wilson 10662c86e55dSMatthew Auld ggtt->vm.clear_range = nop_clear_range; 10672c86e55dSMatthew Auld if (!HAS_FULL_PPGTT(i915) || intel_scanout_needs_vtd_wa(i915)) 10682c86e55dSMatthew Auld ggtt->vm.clear_range = gen6_ggtt_clear_range; 10692c86e55dSMatthew Auld ggtt->vm.insert_page = gen6_ggtt_insert_page; 10702c86e55dSMatthew Auld ggtt->vm.insert_entries = gen6_ggtt_insert_entries; 10712c86e55dSMatthew Auld ggtt->vm.cleanup = gen6_gmch_remove; 10722c86e55dSMatthew Auld 10732c86e55dSMatthew Auld ggtt->invalidate = gen6_ggtt_invalidate; 10742c86e55dSMatthew Auld 10752c86e55dSMatthew Auld if (HAS_EDRAM(i915)) 10762c86e55dSMatthew Auld ggtt->vm.pte_encode = iris_pte_encode; 10772c86e55dSMatthew Auld else if (IS_HASWELL(i915)) 10782c86e55dSMatthew Auld ggtt->vm.pte_encode = hsw_pte_encode; 10792c86e55dSMatthew Auld else if (IS_VALLEYVIEW(i915)) 10802c86e55dSMatthew Auld ggtt->vm.pte_encode = byt_pte_encode; 1081*c816723bSLucas De Marchi else if (GRAPHICS_VER(i915) >= 7) 10822c86e55dSMatthew Auld ggtt->vm.pte_encode = ivb_pte_encode; 10832c86e55dSMatthew Auld else 10842c86e55dSMatthew Auld ggtt->vm.pte_encode = snb_pte_encode; 10852c86e55dSMatthew Auld 10862c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 10872c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 10882c86e55dSMatthew Auld ggtt->vm.vma_ops.set_pages = ggtt_set_pages; 10892c86e55dSMatthew Auld ggtt->vm.vma_ops.clear_pages = clear_pages; 10902c86e55dSMatthew Auld 10912c86e55dSMatthew Auld return ggtt_probe_common(ggtt, size); 10922c86e55dSMatthew Auld } 10932c86e55dSMatthew Auld 10942c86e55dSMatthew Auld static void i915_gmch_remove(struct i915_address_space *vm) 10952c86e55dSMatthew Auld { 10962c86e55dSMatthew Auld intel_gmch_remove(); 10972c86e55dSMatthew Auld } 10982c86e55dSMatthew Auld 10992c86e55dSMatthew Auld static int i915_gmch_probe(struct i915_ggtt *ggtt) 11002c86e55dSMatthew Auld { 11012c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 11022c86e55dSMatthew Auld phys_addr_t gmadr_base; 11032c86e55dSMatthew Auld int ret; 11042c86e55dSMatthew Auld 1105e322551fSThomas Zimmermann ret = intel_gmch_probe(i915->bridge_dev, to_pci_dev(i915->drm.dev), NULL); 11062c86e55dSMatthew Auld if (!ret) { 110736034c95SWambui Karuga drm_err(&i915->drm, "failed to set up gmch\n"); 11082c86e55dSMatthew Auld return -EIO; 11092c86e55dSMatthew Auld } 11102c86e55dSMatthew Auld 11112c86e55dSMatthew Auld intel_gtt_get(&ggtt->vm.total, &gmadr_base, &ggtt->mappable_end); 11122c86e55dSMatthew Auld 11132c86e55dSMatthew Auld ggtt->gmadr = 11142c86e55dSMatthew Auld (struct resource)DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end); 11152c86e55dSMatthew Auld 111689351925SChris Wilson ggtt->vm.alloc_pt_dma = alloc_pt_dma; 111789351925SChris Wilson 111884361529SChris Wilson if (needs_idle_maps(i915)) { 111984361529SChris Wilson drm_notice(&i915->drm, 112084361529SChris Wilson "Flushing DMA requests before IOMMU unmaps; performance may be degraded\n"); 112184361529SChris Wilson ggtt->do_idle_maps = true; 112284361529SChris Wilson } 112384361529SChris Wilson 11242c86e55dSMatthew Auld ggtt->vm.insert_page = i915_ggtt_insert_page; 11252c86e55dSMatthew Auld ggtt->vm.insert_entries = i915_ggtt_insert_entries; 11262c86e55dSMatthew Auld ggtt->vm.clear_range = i915_ggtt_clear_range; 11272c86e55dSMatthew Auld ggtt->vm.cleanup = i915_gmch_remove; 11282c86e55dSMatthew Auld 11292c86e55dSMatthew Auld ggtt->invalidate = gmch_ggtt_invalidate; 11302c86e55dSMatthew Auld 11312c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 11322c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 11332c86e55dSMatthew Auld ggtt->vm.vma_ops.set_pages = ggtt_set_pages; 11342c86e55dSMatthew Auld ggtt->vm.vma_ops.clear_pages = clear_pages; 11352c86e55dSMatthew Auld 11362c86e55dSMatthew Auld if (unlikely(ggtt->do_idle_maps)) 1137dc483ba5SJani Nikula drm_notice(&i915->drm, 11382c86e55dSMatthew Auld "Applying Ironlake quirks for intel_iommu\n"); 11392c86e55dSMatthew Auld 11402c86e55dSMatthew Auld return 0; 11412c86e55dSMatthew Auld } 11422c86e55dSMatthew Auld 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 1153*c816723bSLucas De Marchi if (GRAPHICS_VER(i915) <= 5) 11542c86e55dSMatthew Auld ret = i915_gmch_probe(ggtt); 1155*c816723bSLucas De Marchi else if (GRAPHICS_VER(i915) < 8) 11562c86e55dSMatthew Auld ret = gen6_gmch_probe(ggtt); 11572c86e55dSMatthew Auld else 11582c86e55dSMatthew Auld ret = gen8_gmch_probe(ggtt); 115926ad4f8bSMaarten Lankhorst if (ret) { 11604d8151aeSThomas Hellström dma_resv_fini(&ggtt->vm._resv); 11612c86e55dSMatthew Auld return ret; 116226ad4f8bSMaarten Lankhorst } 11632c86e55dSMatthew Auld 11642c86e55dSMatthew Auld if ((ggtt->vm.total - 1) >> 32) { 116536034c95SWambui Karuga drm_err(&i915->drm, 116636034c95SWambui Karuga "We never expected a Global GTT with more than 32bits" 11672c86e55dSMatthew Auld " of address space! Found %lldM!\n", 11682c86e55dSMatthew Auld ggtt->vm.total >> 20); 11692c86e55dSMatthew Auld ggtt->vm.total = 1ULL << 32; 11702c86e55dSMatthew Auld ggtt->mappable_end = 11712c86e55dSMatthew Auld min_t(u64, ggtt->mappable_end, ggtt->vm.total); 11722c86e55dSMatthew Auld } 11732c86e55dSMatthew Auld 11742c86e55dSMatthew Auld if (ggtt->mappable_end > ggtt->vm.total) { 117536034c95SWambui Karuga drm_err(&i915->drm, 117636034c95SWambui Karuga "mappable aperture extends past end of GGTT," 11772c86e55dSMatthew Auld " aperture=%pa, total=%llx\n", 11782c86e55dSMatthew Auld &ggtt->mappable_end, ggtt->vm.total); 11792c86e55dSMatthew Auld ggtt->mappable_end = ggtt->vm.total; 11802c86e55dSMatthew Auld } 11812c86e55dSMatthew Auld 11822c86e55dSMatthew Auld /* GMADR is the PCI mmio aperture into the global GTT. */ 118336034c95SWambui Karuga drm_dbg(&i915->drm, "GGTT size = %lluM\n", ggtt->vm.total >> 20); 118436034c95SWambui Karuga drm_dbg(&i915->drm, "GMADR size = %lluM\n", 118536034c95SWambui Karuga (u64)ggtt->mappable_end >> 20); 118636034c95SWambui Karuga drm_dbg(&i915->drm, "DSM size = %lluM\n", 11872c86e55dSMatthew Auld (u64)resource_size(&intel_graphics_stolen_res) >> 20); 11882c86e55dSMatthew Auld 11892c86e55dSMatthew Auld return 0; 11902c86e55dSMatthew Auld } 11912c86e55dSMatthew Auld 11922c86e55dSMatthew Auld /** 11932c86e55dSMatthew Auld * i915_ggtt_probe_hw - Probe GGTT hardware location 11942c86e55dSMatthew Auld * @i915: i915 device 11952c86e55dSMatthew Auld */ 11962c86e55dSMatthew Auld int i915_ggtt_probe_hw(struct drm_i915_private *i915) 11972c86e55dSMatthew Auld { 11982c86e55dSMatthew Auld int ret; 11992c86e55dSMatthew Auld 12002c86e55dSMatthew Auld ret = ggtt_probe_hw(&i915->ggtt, &i915->gt); 12012c86e55dSMatthew Auld if (ret) 12022c86e55dSMatthew Auld return ret; 12032c86e55dSMatthew Auld 12042c86e55dSMatthew Auld if (intel_vtd_active()) 1205dc483ba5SJani Nikula drm_info(&i915->drm, "VT-d active for gfx access\n"); 12062c86e55dSMatthew Auld 12072c86e55dSMatthew Auld return 0; 12082c86e55dSMatthew Auld } 12092c86e55dSMatthew Auld 12102c86e55dSMatthew Auld int i915_ggtt_enable_hw(struct drm_i915_private *i915) 12112c86e55dSMatthew Auld { 1212*c816723bSLucas De Marchi if (GRAPHICS_VER(i915) < 6 && !intel_enable_gtt()) 12132c86e55dSMatthew Auld return -EIO; 12142c86e55dSMatthew Auld 12152c86e55dSMatthew Auld return 0; 12162c86e55dSMatthew Auld } 12172c86e55dSMatthew Auld 12182c86e55dSMatthew Auld void i915_ggtt_enable_guc(struct i915_ggtt *ggtt) 12192c86e55dSMatthew Auld { 12202c86e55dSMatthew Auld GEM_BUG_ON(ggtt->invalidate != gen8_ggtt_invalidate); 12212c86e55dSMatthew Auld 12222c86e55dSMatthew Auld ggtt->invalidate = guc_ggtt_invalidate; 12232c86e55dSMatthew Auld 12242c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12252c86e55dSMatthew Auld } 12262c86e55dSMatthew Auld 12272c86e55dSMatthew Auld void i915_ggtt_disable_guc(struct i915_ggtt *ggtt) 12282c86e55dSMatthew Auld { 12292c86e55dSMatthew Auld /* XXX Temporary pardon for error unload */ 12302c86e55dSMatthew Auld if (ggtt->invalidate == gen8_ggtt_invalidate) 12312c86e55dSMatthew Auld return; 12322c86e55dSMatthew Auld 12332c86e55dSMatthew Auld /* We should only be called after i915_ggtt_enable_guc() */ 12342c86e55dSMatthew Auld GEM_BUG_ON(ggtt->invalidate != guc_ggtt_invalidate); 12352c86e55dSMatthew Auld 12362c86e55dSMatthew Auld ggtt->invalidate = gen8_ggtt_invalidate; 12372c86e55dSMatthew Auld 12382c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12392c86e55dSMatthew Auld } 12402c86e55dSMatthew Auld 1241e986209cSChris Wilson void i915_ggtt_resume(struct i915_ggtt *ggtt) 12422c86e55dSMatthew Auld { 124380e5351dSChris Wilson struct i915_vma *vma; 12442c86e55dSMatthew Auld bool flush = false; 12452c86e55dSMatthew Auld int open; 12462c86e55dSMatthew Auld 12472c86e55dSMatthew Auld intel_gt_check_and_clear_faults(ggtt->vm.gt); 12482c86e55dSMatthew Auld 12492c86e55dSMatthew Auld /* First fill our portion of the GTT with scratch pages */ 12502c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, 0, ggtt->vm.total); 12512c86e55dSMatthew Auld 12522c86e55dSMatthew Auld /* Skip rewriting PTE on VMA unbind. */ 12532c86e55dSMatthew Auld open = atomic_xchg(&ggtt->vm.open, 0); 12542c86e55dSMatthew Auld 12552c86e55dSMatthew Auld /* clflush objects bound into the GGTT and rebind them. */ 125680e5351dSChris Wilson list_for_each_entry(vma, &ggtt->vm.bound_list, vm_link) { 12572c86e55dSMatthew Auld struct drm_i915_gem_object *obj = vma->obj; 1258cd0452aaSChris Wilson unsigned int was_bound = 1259cd0452aaSChris Wilson atomic_read(&vma->flags) & I915_VMA_BIND_MASK; 12602c86e55dSMatthew Auld 1261cd0452aaSChris Wilson GEM_BUG_ON(!was_bound); 1262cd0452aaSChris Wilson vma->ops->bind_vma(&ggtt->vm, NULL, vma, 12632c86e55dSMatthew Auld obj ? obj->cache_level : 0, 1264cd0452aaSChris Wilson was_bound); 12652c86e55dSMatthew Auld if (obj) { /* only used during resume => exclusive access */ 12662c86e55dSMatthew Auld flush |= fetch_and_zero(&obj->write_domain); 12672c86e55dSMatthew Auld obj->read_domains |= I915_GEM_DOMAIN_GTT; 12682c86e55dSMatthew Auld } 12692c86e55dSMatthew Auld } 12702c86e55dSMatthew Auld 12712c86e55dSMatthew Auld atomic_set(&ggtt->vm.open, open); 12722c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12732c86e55dSMatthew Auld 12742c86e55dSMatthew Auld if (flush) 12752c86e55dSMatthew Auld wbinvd_on_all_cpus(); 12762c86e55dSMatthew Auld 1277*c816723bSLucas De Marchi if (GRAPHICS_VER(ggtt->vm.i915) >= 8) 12782c86e55dSMatthew Auld setup_private_pat(ggtt->vm.gt->uncore); 1279dec9cf9eSChris Wilson 1280dec9cf9eSChris Wilson intel_ggtt_restore_fences(ggtt); 12812c86e55dSMatthew Auld } 12822c86e55dSMatthew Auld 12832c86e55dSMatthew Auld static struct scatterlist * 12842c86e55dSMatthew Auld rotate_pages(struct drm_i915_gem_object *obj, unsigned int offset, 12852c86e55dSMatthew Auld unsigned int width, unsigned int height, 1286a4606d45SImre Deak unsigned int src_stride, unsigned int dst_stride, 12872c86e55dSMatthew Auld struct sg_table *st, struct scatterlist *sg) 12882c86e55dSMatthew Auld { 12892c86e55dSMatthew Auld unsigned int column, row; 12902c86e55dSMatthew Auld unsigned int src_idx; 12912c86e55dSMatthew Auld 12922c86e55dSMatthew Auld for (column = 0; column < width; column++) { 1293a4606d45SImre Deak unsigned int left; 1294a4606d45SImre Deak 1295a4606d45SImre Deak src_idx = src_stride * (height - 1) + column + offset; 12962c86e55dSMatthew Auld for (row = 0; row < height; row++) { 12972c86e55dSMatthew Auld st->nents++; 12982c86e55dSMatthew Auld /* 12992c86e55dSMatthew Auld * We don't need the pages, but need to initialize 13002c86e55dSMatthew Auld * the entries so the sg list can be happily traversed. 13012c86e55dSMatthew Auld * The only thing we need are DMA addresses. 13022c86e55dSMatthew Auld */ 13032c86e55dSMatthew Auld sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0); 13042c86e55dSMatthew Auld sg_dma_address(sg) = 13052c86e55dSMatthew Auld i915_gem_object_get_dma_address(obj, src_idx); 13062c86e55dSMatthew Auld sg_dma_len(sg) = I915_GTT_PAGE_SIZE; 13072c86e55dSMatthew Auld sg = sg_next(sg); 1308a4606d45SImre Deak src_idx -= src_stride; 13092c86e55dSMatthew Auld } 1310a4606d45SImre Deak 1311a4606d45SImre Deak left = (dst_stride - height) * I915_GTT_PAGE_SIZE; 1312a4606d45SImre Deak 1313a4606d45SImre Deak if (!left) 1314a4606d45SImre Deak continue; 1315a4606d45SImre Deak 1316a4606d45SImre Deak st->nents++; 1317a4606d45SImre Deak 1318a4606d45SImre Deak /* 1319a4606d45SImre Deak * The DE ignores the PTEs for the padding tiles, the sg entry 1320a4606d45SImre Deak * here is just a conenience to indicate how many padding PTEs 1321a4606d45SImre Deak * to insert at this spot. 1322a4606d45SImre Deak */ 1323a4606d45SImre Deak sg_set_page(sg, NULL, left, 0); 1324a4606d45SImre Deak sg_dma_address(sg) = 0; 1325a4606d45SImre Deak sg_dma_len(sg) = left; 1326a4606d45SImre Deak sg = sg_next(sg); 13272c86e55dSMatthew Auld } 13282c86e55dSMatthew Auld 13292c86e55dSMatthew Auld return sg; 13302c86e55dSMatthew Auld } 13312c86e55dSMatthew Auld 13322c86e55dSMatthew Auld static noinline struct sg_table * 13332c86e55dSMatthew Auld intel_rotate_pages(struct intel_rotation_info *rot_info, 13342c86e55dSMatthew Auld struct drm_i915_gem_object *obj) 13352c86e55dSMatthew Auld { 13362c86e55dSMatthew Auld unsigned int size = intel_rotation_info_size(rot_info); 133752ce7074SWambui Karuga struct drm_i915_private *i915 = to_i915(obj->base.dev); 13382c86e55dSMatthew Auld struct sg_table *st; 13392c86e55dSMatthew Auld struct scatterlist *sg; 13402c86e55dSMatthew Auld int ret = -ENOMEM; 13412c86e55dSMatthew Auld int i; 13422c86e55dSMatthew Auld 13432c86e55dSMatthew Auld /* Allocate target SG list. */ 13442c86e55dSMatthew Auld st = kmalloc(sizeof(*st), GFP_KERNEL); 13452c86e55dSMatthew Auld if (!st) 13462c86e55dSMatthew Auld goto err_st_alloc; 13472c86e55dSMatthew Auld 13482c86e55dSMatthew Auld ret = sg_alloc_table(st, size, GFP_KERNEL); 13492c86e55dSMatthew Auld if (ret) 13502c86e55dSMatthew Auld goto err_sg_alloc; 13512c86e55dSMatthew Auld 13522c86e55dSMatthew Auld st->nents = 0; 13532c86e55dSMatthew Auld sg = st->sgl; 13542c86e55dSMatthew Auld 1355a4606d45SImre Deak for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) 13562c86e55dSMatthew Auld sg = rotate_pages(obj, rot_info->plane[i].offset, 13572c86e55dSMatthew Auld rot_info->plane[i].width, rot_info->plane[i].height, 1358a4606d45SImre Deak rot_info->plane[i].src_stride, 1359a4606d45SImre Deak rot_info->plane[i].dst_stride, 1360a4606d45SImre Deak st, sg); 13612c86e55dSMatthew Auld 13622c86e55dSMatthew Auld return st; 13632c86e55dSMatthew Auld 13642c86e55dSMatthew Auld err_sg_alloc: 13652c86e55dSMatthew Auld kfree(st); 13662c86e55dSMatthew Auld err_st_alloc: 13672c86e55dSMatthew Auld 136852ce7074SWambui Karuga drm_dbg(&i915->drm, "Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n", 136952ce7074SWambui Karuga obj->base.size, rot_info->plane[0].width, 137052ce7074SWambui Karuga rot_info->plane[0].height, size); 13712c86e55dSMatthew Auld 13722c86e55dSMatthew Auld return ERR_PTR(ret); 13732c86e55dSMatthew Auld } 13742c86e55dSMatthew Auld 13752c86e55dSMatthew Auld static struct scatterlist * 13762c86e55dSMatthew Auld remap_pages(struct drm_i915_gem_object *obj, unsigned int offset, 13772c86e55dSMatthew Auld unsigned int width, unsigned int height, 1378a4606d45SImre Deak unsigned int src_stride, unsigned int dst_stride, 13792c86e55dSMatthew Auld struct sg_table *st, struct scatterlist *sg) 13802c86e55dSMatthew Auld { 13812c86e55dSMatthew Auld unsigned int row; 13822c86e55dSMatthew Auld 13832c86e55dSMatthew Auld for (row = 0; row < height; row++) { 13842c86e55dSMatthew Auld unsigned int left = width * I915_GTT_PAGE_SIZE; 13852c86e55dSMatthew Auld 13862c86e55dSMatthew Auld while (left) { 13872c86e55dSMatthew Auld dma_addr_t addr; 13882c86e55dSMatthew Auld unsigned int length; 13892c86e55dSMatthew Auld 13902c86e55dSMatthew Auld /* 13912c86e55dSMatthew Auld * We don't need the pages, but need to initialize 13922c86e55dSMatthew Auld * the entries so the sg list can be happily traversed. 13932c86e55dSMatthew Auld * The only thing we need are DMA addresses. 13942c86e55dSMatthew Auld */ 13952c86e55dSMatthew Auld 13962c86e55dSMatthew Auld addr = i915_gem_object_get_dma_address_len(obj, offset, &length); 13972c86e55dSMatthew Auld 13982c86e55dSMatthew Auld length = min(left, length); 13992c86e55dSMatthew Auld 14002c86e55dSMatthew Auld st->nents++; 14012c86e55dSMatthew Auld 14022c86e55dSMatthew Auld sg_set_page(sg, NULL, length, 0); 14032c86e55dSMatthew Auld sg_dma_address(sg) = addr; 14042c86e55dSMatthew Auld sg_dma_len(sg) = length; 14052c86e55dSMatthew Auld sg = sg_next(sg); 14062c86e55dSMatthew Auld 14072c86e55dSMatthew Auld offset += length / I915_GTT_PAGE_SIZE; 14082c86e55dSMatthew Auld left -= length; 14092c86e55dSMatthew Auld } 14102c86e55dSMatthew Auld 1411a4606d45SImre Deak offset += src_stride - width; 1412a4606d45SImre Deak 1413a4606d45SImre Deak left = (dst_stride - width) * I915_GTT_PAGE_SIZE; 1414a4606d45SImre Deak 1415a4606d45SImre Deak if (!left) 1416a4606d45SImre Deak continue; 1417a4606d45SImre Deak 1418a4606d45SImre Deak st->nents++; 1419a4606d45SImre Deak 1420a4606d45SImre Deak /* 1421a4606d45SImre Deak * The DE ignores the PTEs for the padding tiles, the sg entry 1422a4606d45SImre Deak * here is just a conenience to indicate how many padding PTEs 1423a4606d45SImre Deak * to insert at this spot. 1424a4606d45SImre Deak */ 1425a4606d45SImre Deak sg_set_page(sg, NULL, left, 0); 1426a4606d45SImre Deak sg_dma_address(sg) = 0; 1427a4606d45SImre Deak sg_dma_len(sg) = left; 1428a4606d45SImre Deak sg = sg_next(sg); 14292c86e55dSMatthew Auld } 14302c86e55dSMatthew Auld 14312c86e55dSMatthew Auld return sg; 14322c86e55dSMatthew Auld } 14332c86e55dSMatthew Auld 14342c86e55dSMatthew Auld static noinline struct sg_table * 14352c86e55dSMatthew Auld intel_remap_pages(struct intel_remapped_info *rem_info, 14362c86e55dSMatthew Auld struct drm_i915_gem_object *obj) 14372c86e55dSMatthew Auld { 14382c86e55dSMatthew Auld unsigned int size = intel_remapped_info_size(rem_info); 143952ce7074SWambui Karuga struct drm_i915_private *i915 = to_i915(obj->base.dev); 14402c86e55dSMatthew Auld struct sg_table *st; 14412c86e55dSMatthew Auld struct scatterlist *sg; 14422c86e55dSMatthew Auld int ret = -ENOMEM; 14432c86e55dSMatthew Auld int i; 14442c86e55dSMatthew Auld 14452c86e55dSMatthew Auld /* Allocate target SG list. */ 14462c86e55dSMatthew Auld st = kmalloc(sizeof(*st), GFP_KERNEL); 14472c86e55dSMatthew Auld if (!st) 14482c86e55dSMatthew Auld goto err_st_alloc; 14492c86e55dSMatthew Auld 14502c86e55dSMatthew Auld ret = sg_alloc_table(st, size, GFP_KERNEL); 14512c86e55dSMatthew Auld if (ret) 14522c86e55dSMatthew Auld goto err_sg_alloc; 14532c86e55dSMatthew Auld 14542c86e55dSMatthew Auld st->nents = 0; 14552c86e55dSMatthew Auld sg = st->sgl; 14562c86e55dSMatthew Auld 14572c86e55dSMatthew Auld for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { 14582c86e55dSMatthew Auld sg = remap_pages(obj, rem_info->plane[i].offset, 14592c86e55dSMatthew Auld rem_info->plane[i].width, rem_info->plane[i].height, 1460a4606d45SImre Deak rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride, 1461a4606d45SImre Deak st, sg); 14622c86e55dSMatthew Auld } 14632c86e55dSMatthew Auld 14642c86e55dSMatthew Auld i915_sg_trim(st); 14652c86e55dSMatthew Auld 14662c86e55dSMatthew Auld return st; 14672c86e55dSMatthew Auld 14682c86e55dSMatthew Auld err_sg_alloc: 14692c86e55dSMatthew Auld kfree(st); 14702c86e55dSMatthew Auld err_st_alloc: 14712c86e55dSMatthew Auld 147252ce7074SWambui Karuga drm_dbg(&i915->drm, "Failed to create remapped mapping for object size %zu! (%ux%u tiles, %u pages)\n", 147352ce7074SWambui Karuga obj->base.size, rem_info->plane[0].width, 147452ce7074SWambui Karuga rem_info->plane[0].height, size); 14752c86e55dSMatthew Auld 14762c86e55dSMatthew Auld return ERR_PTR(ret); 14772c86e55dSMatthew Auld } 14782c86e55dSMatthew Auld 14792c86e55dSMatthew Auld static noinline struct sg_table * 14802c86e55dSMatthew Auld intel_partial_pages(const struct i915_ggtt_view *view, 14812c86e55dSMatthew Auld struct drm_i915_gem_object *obj) 14822c86e55dSMatthew Auld { 14832c86e55dSMatthew Auld struct sg_table *st; 14842c86e55dSMatthew Auld struct scatterlist *sg, *iter; 14852c86e55dSMatthew Auld unsigned int count = view->partial.size; 14862c86e55dSMatthew Auld unsigned int offset; 14872c86e55dSMatthew Auld int ret = -ENOMEM; 14882c86e55dSMatthew Auld 14892c86e55dSMatthew Auld st = kmalloc(sizeof(*st), GFP_KERNEL); 14902c86e55dSMatthew Auld if (!st) 14912c86e55dSMatthew Auld goto err_st_alloc; 14922c86e55dSMatthew Auld 14932c86e55dSMatthew Auld ret = sg_alloc_table(st, count, GFP_KERNEL); 14942c86e55dSMatthew Auld if (ret) 14952c86e55dSMatthew Auld goto err_sg_alloc; 14962c86e55dSMatthew Auld 14970edbb9baSMaarten Lankhorst iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset, true); 14982c86e55dSMatthew Auld GEM_BUG_ON(!iter); 14992c86e55dSMatthew Auld 15002c86e55dSMatthew Auld sg = st->sgl; 15012c86e55dSMatthew Auld st->nents = 0; 15022c86e55dSMatthew Auld do { 15032c86e55dSMatthew Auld unsigned int len; 15042c86e55dSMatthew Auld 1505934941edSTvrtko Ursulin len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), 15062c86e55dSMatthew Auld count << PAGE_SHIFT); 15072c86e55dSMatthew Auld sg_set_page(sg, NULL, len, 0); 15082c86e55dSMatthew Auld sg_dma_address(sg) = 15092c86e55dSMatthew Auld sg_dma_address(iter) + (offset << PAGE_SHIFT); 15102c86e55dSMatthew Auld sg_dma_len(sg) = len; 15112c86e55dSMatthew Auld 15122c86e55dSMatthew Auld st->nents++; 15132c86e55dSMatthew Auld count -= len >> PAGE_SHIFT; 15142c86e55dSMatthew Auld if (count == 0) { 15152c86e55dSMatthew Auld sg_mark_end(sg); 15162c86e55dSMatthew Auld i915_sg_trim(st); /* Drop any unused tail entries. */ 15172c86e55dSMatthew Auld 15182c86e55dSMatthew Auld return st; 15192c86e55dSMatthew Auld } 15202c86e55dSMatthew Auld 15212c86e55dSMatthew Auld sg = __sg_next(sg); 15222c86e55dSMatthew Auld iter = __sg_next(iter); 15232c86e55dSMatthew Auld offset = 0; 15242c86e55dSMatthew Auld } while (1); 15252c86e55dSMatthew Auld 15262c86e55dSMatthew Auld err_sg_alloc: 15272c86e55dSMatthew Auld kfree(st); 15282c86e55dSMatthew Auld err_st_alloc: 15292c86e55dSMatthew Auld return ERR_PTR(ret); 15302c86e55dSMatthew Auld } 15312c86e55dSMatthew Auld 15322c86e55dSMatthew Auld static int 15332c86e55dSMatthew Auld i915_get_ggtt_vma_pages(struct i915_vma *vma) 15342c86e55dSMatthew Auld { 15352c86e55dSMatthew Auld int ret; 15362c86e55dSMatthew Auld 15372c86e55dSMatthew Auld /* 15382c86e55dSMatthew Auld * The vma->pages are only valid within the lifespan of the borrowed 15392c86e55dSMatthew Auld * obj->mm.pages. When the obj->mm.pages sg_table is regenerated, so 15402c86e55dSMatthew Auld * must be the vma->pages. A simple rule is that vma->pages must only 15412c86e55dSMatthew Auld * be accessed when the obj->mm.pages are pinned. 15422c86e55dSMatthew Auld */ 15432c86e55dSMatthew Auld GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj)); 15442c86e55dSMatthew Auld 15452c86e55dSMatthew Auld switch (vma->ggtt_view.type) { 15462c86e55dSMatthew Auld default: 15472c86e55dSMatthew Auld GEM_BUG_ON(vma->ggtt_view.type); 1548df561f66SGustavo A. R. Silva fallthrough; 15492c86e55dSMatthew Auld case I915_GGTT_VIEW_NORMAL: 15502c86e55dSMatthew Auld vma->pages = vma->obj->mm.pages; 15512c86e55dSMatthew Auld return 0; 15522c86e55dSMatthew Auld 15532c86e55dSMatthew Auld case I915_GGTT_VIEW_ROTATED: 15542c86e55dSMatthew Auld vma->pages = 15552c86e55dSMatthew Auld intel_rotate_pages(&vma->ggtt_view.rotated, vma->obj); 15562c86e55dSMatthew Auld break; 15572c86e55dSMatthew Auld 15582c86e55dSMatthew Auld case I915_GGTT_VIEW_REMAPPED: 15592c86e55dSMatthew Auld vma->pages = 15602c86e55dSMatthew Auld intel_remap_pages(&vma->ggtt_view.remapped, vma->obj); 15612c86e55dSMatthew Auld break; 15622c86e55dSMatthew Auld 15632c86e55dSMatthew Auld case I915_GGTT_VIEW_PARTIAL: 15642c86e55dSMatthew Auld vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj); 15652c86e55dSMatthew Auld break; 15662c86e55dSMatthew Auld } 15672c86e55dSMatthew Auld 15682c86e55dSMatthew Auld ret = 0; 15692c86e55dSMatthew Auld if (IS_ERR(vma->pages)) { 15702c86e55dSMatthew Auld ret = PTR_ERR(vma->pages); 15712c86e55dSMatthew Auld vma->pages = NULL; 157252ce7074SWambui Karuga drm_err(&vma->vm->i915->drm, 157352ce7074SWambui Karuga "Failed to get pages for VMA view type %u (%d)!\n", 15742c86e55dSMatthew Auld vma->ggtt_view.type, ret); 15752c86e55dSMatthew Auld } 15762c86e55dSMatthew Auld return ret; 15772c86e55dSMatthew Auld } 1578