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" 212c86e55dSMatthew Auld 222c86e55dSMatthew Auld static int 232c86e55dSMatthew Auld i915_get_ggtt_vma_pages(struct i915_vma *vma); 242c86e55dSMatthew Auld 252c86e55dSMatthew Auld static void i915_ggtt_color_adjust(const struct drm_mm_node *node, 262c86e55dSMatthew Auld unsigned long color, 272c86e55dSMatthew Auld u64 *start, 282c86e55dSMatthew Auld u64 *end) 292c86e55dSMatthew Auld { 302c86e55dSMatthew Auld if (i915_node_color_differs(node, color)) 312c86e55dSMatthew Auld *start += I915_GTT_PAGE_SIZE; 322c86e55dSMatthew Auld 332c86e55dSMatthew Auld /* 342c86e55dSMatthew Auld * Also leave a space between the unallocated reserved node after the 352c86e55dSMatthew Auld * GTT and any objects within the GTT, i.e. we use the color adjustment 362c86e55dSMatthew Auld * to insert a guard page to prevent prefetches crossing over the 372c86e55dSMatthew Auld * GTT boundary. 382c86e55dSMatthew Auld */ 392c86e55dSMatthew Auld node = list_next_entry(node, node_list); 402c86e55dSMatthew Auld if (node->color != color) 412c86e55dSMatthew Auld *end -= I915_GTT_PAGE_SIZE; 422c86e55dSMatthew Auld } 432c86e55dSMatthew Auld 442c86e55dSMatthew Auld static int ggtt_init_hw(struct i915_ggtt *ggtt) 452c86e55dSMatthew Auld { 462c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 472c86e55dSMatthew Auld 482c86e55dSMatthew Auld i915_address_space_init(&ggtt->vm, VM_CLASS_GGTT); 492c86e55dSMatthew Auld 502c86e55dSMatthew Auld ggtt->vm.is_ggtt = true; 512c86e55dSMatthew Auld 522c86e55dSMatthew Auld /* Only VLV supports read-only GGTT mappings */ 532c86e55dSMatthew Auld ggtt->vm.has_read_only = IS_VALLEYVIEW(i915); 542c86e55dSMatthew Auld 552c86e55dSMatthew Auld if (!HAS_LLC(i915) && !HAS_PPGTT(i915)) 562c86e55dSMatthew Auld ggtt->vm.mm.color_adjust = i915_ggtt_color_adjust; 572c86e55dSMatthew Auld 582c86e55dSMatthew Auld if (ggtt->mappable_end) { 592c86e55dSMatthew Auld if (!io_mapping_init_wc(&ggtt->iomap, 602c86e55dSMatthew Auld ggtt->gmadr.start, 612c86e55dSMatthew Auld ggtt->mappable_end)) { 622c86e55dSMatthew Auld ggtt->vm.cleanup(&ggtt->vm); 632c86e55dSMatthew Auld return -EIO; 642c86e55dSMatthew Auld } 652c86e55dSMatthew Auld 662c86e55dSMatthew Auld ggtt->mtrr = arch_phys_wc_add(ggtt->gmadr.start, 672c86e55dSMatthew Auld ggtt->mappable_end); 682c86e55dSMatthew Auld } 692c86e55dSMatthew Auld 70f899f786SChris Wilson intel_ggtt_init_fences(ggtt); 712c86e55dSMatthew Auld 722c86e55dSMatthew Auld return 0; 732c86e55dSMatthew Auld } 742c86e55dSMatthew Auld 752c86e55dSMatthew Auld /** 762c86e55dSMatthew Auld * i915_ggtt_init_hw - Initialize GGTT hardware 772c86e55dSMatthew Auld * @i915: i915 device 782c86e55dSMatthew Auld */ 792c86e55dSMatthew Auld int i915_ggtt_init_hw(struct drm_i915_private *i915) 802c86e55dSMatthew Auld { 812c86e55dSMatthew Auld int ret; 822c86e55dSMatthew Auld 832c86e55dSMatthew Auld /* 842c86e55dSMatthew Auld * Note that we use page colouring to enforce a guard page at the 852c86e55dSMatthew Auld * end of the address space. This is required as the CS may prefetch 862c86e55dSMatthew Auld * beyond the end of the batch buffer, across the page boundary, 872c86e55dSMatthew Auld * and beyond the end of the GTT if we do not provide a guard. 882c86e55dSMatthew Auld */ 892c86e55dSMatthew Auld ret = ggtt_init_hw(&i915->ggtt); 902c86e55dSMatthew Auld if (ret) 912c86e55dSMatthew Auld return ret; 922c86e55dSMatthew Auld 932c86e55dSMatthew Auld return 0; 942c86e55dSMatthew Auld } 952c86e55dSMatthew Auld 962c86e55dSMatthew Auld /* 971ca9b8daSChris Wilson * Certain Gen5 chipsets require idling the GPU before 982c86e55dSMatthew Auld * unmapping anything from the GTT when VT-d is enabled. 992c86e55dSMatthew Auld */ 1002c86e55dSMatthew Auld static bool needs_idle_maps(struct drm_i915_private *i915) 1012c86e55dSMatthew Auld { 1022c86e55dSMatthew Auld /* 1032c86e55dSMatthew Auld * Query intel_iommu to see if we need the workaround. Presumably that 1042c86e55dSMatthew Auld * was loaded first. 1052c86e55dSMatthew Auld */ 10684361529SChris Wilson if (!intel_vtd_active()) 10784361529SChris Wilson return false; 10884361529SChris Wilson 10984361529SChris Wilson if (IS_GEN(i915, 5) && IS_MOBILE(i915)) 11084361529SChris Wilson return true; 11184361529SChris Wilson 11284361529SChris Wilson if (IS_GEN(i915, 12)) 11384361529SChris Wilson return true; /* XXX DMAR fault reason 7 */ 11484361529SChris Wilson 11584361529SChris Wilson return false; 1162c86e55dSMatthew Auld } 1172c86e55dSMatthew Auld 118e986209cSChris Wilson void i915_ggtt_suspend(struct i915_ggtt *ggtt) 1192c86e55dSMatthew Auld { 120bffa18ddSChris Wilson struct i915_vma *vma, *vn; 121bffa18ddSChris Wilson int open; 122e3793468SChris Wilson 123bffa18ddSChris Wilson mutex_lock(&ggtt->vm.mutex); 124bffa18ddSChris Wilson 125bffa18ddSChris Wilson /* Skip rewriting PTE on VMA unbind. */ 126bffa18ddSChris Wilson open = atomic_xchg(&ggtt->vm.open, 0); 127bffa18ddSChris Wilson 128bffa18ddSChris Wilson list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) { 129bffa18ddSChris Wilson GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); 130e3793468SChris Wilson i915_vma_wait_for_bind(vma); 131e3793468SChris Wilson 132bffa18ddSChris Wilson if (i915_vma_is_pinned(vma)) 133bffa18ddSChris Wilson continue; 134bffa18ddSChris Wilson 135bffa18ddSChris Wilson if (!i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) { 136bffa18ddSChris Wilson __i915_vma_evict(vma); 137bffa18ddSChris Wilson drm_mm_remove_node(&vma->node); 138bffa18ddSChris Wilson } 139bffa18ddSChris Wilson } 140bffa18ddSChris Wilson 141e986209cSChris Wilson ggtt->vm.clear_range(&ggtt->vm, 0, ggtt->vm.total); 142e986209cSChris Wilson ggtt->invalidate(ggtt); 143bffa18ddSChris Wilson atomic_set(&ggtt->vm.open, open); 144bffa18ddSChris Wilson 145bffa18ddSChris Wilson mutex_unlock(&ggtt->vm.mutex); 1462c86e55dSMatthew Auld 1472c86e55dSMatthew Auld intel_gt_check_and_clear_faults(ggtt->vm.gt); 1482c86e55dSMatthew Auld } 1492c86e55dSMatthew Auld 1502c86e55dSMatthew Auld void gen6_ggtt_invalidate(struct i915_ggtt *ggtt) 1512c86e55dSMatthew Auld { 1522c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 1532c86e55dSMatthew Auld 1542c86e55dSMatthew Auld spin_lock_irq(&uncore->lock); 1552c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); 1562c86e55dSMatthew Auld intel_uncore_read_fw(uncore, GFX_FLSH_CNTL_GEN6); 1572c86e55dSMatthew Auld spin_unlock_irq(&uncore->lock); 1582c86e55dSMatthew Auld } 1592c86e55dSMatthew Auld 1602c86e55dSMatthew Auld static void gen8_ggtt_invalidate(struct i915_ggtt *ggtt) 1612c86e55dSMatthew Auld { 1622c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 1632c86e55dSMatthew Auld 1642c86e55dSMatthew Auld /* 1652c86e55dSMatthew Auld * Note that as an uncached mmio write, this will flush the 1662c86e55dSMatthew Auld * WCB of the writes into the GGTT before it triggers the invalidate. 1672c86e55dSMatthew Auld */ 1682c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); 1692c86e55dSMatthew Auld } 1702c86e55dSMatthew Auld 1712c86e55dSMatthew Auld static void guc_ggtt_invalidate(struct i915_ggtt *ggtt) 1722c86e55dSMatthew Auld { 1732c86e55dSMatthew Auld struct intel_uncore *uncore = ggtt->vm.gt->uncore; 1742c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 1752c86e55dSMatthew Auld 1762c86e55dSMatthew Auld gen8_ggtt_invalidate(ggtt); 1772c86e55dSMatthew Auld 1782c86e55dSMatthew Auld if (INTEL_GEN(i915) >= 12) 1792c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GEN12_GUC_TLB_INV_CR, 1802c86e55dSMatthew Auld GEN12_GUC_TLB_INV_CR_INVALIDATE); 1812c86e55dSMatthew Auld else 1822c86e55dSMatthew Auld intel_uncore_write_fw(uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE); 1832c86e55dSMatthew Auld } 1842c86e55dSMatthew Auld 1852c86e55dSMatthew Auld static void gmch_ggtt_invalidate(struct i915_ggtt *ggtt) 1862c86e55dSMatthew Auld { 1872c86e55dSMatthew Auld intel_gtt_chipset_flush(); 1882c86e55dSMatthew Auld } 1892c86e55dSMatthew Auld 19069edc390SDaniele Ceraolo Spurio static u64 gen8_ggtt_pte_encode(dma_addr_t addr, 19169edc390SDaniele Ceraolo Spurio enum i915_cache_level level, 19269edc390SDaniele Ceraolo Spurio u32 flags) 19369edc390SDaniele Ceraolo Spurio { 194e762bdf5SMatthew Auld gen8_pte_t pte = addr | _PAGE_PRESENT; 195e762bdf5SMatthew Auld 196e762bdf5SMatthew Auld if (flags & PTE_LM) 197e762bdf5SMatthew Auld pte |= GEN12_GGTT_PTE_LM; 198e762bdf5SMatthew Auld 199e762bdf5SMatthew Auld return pte; 20069edc390SDaniele Ceraolo Spurio } 20169edc390SDaniele Ceraolo Spurio 2022c86e55dSMatthew Auld static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte) 2032c86e55dSMatthew Auld { 2042c86e55dSMatthew Auld writeq(pte, addr); 2052c86e55dSMatthew Auld } 2062c86e55dSMatthew Auld 2072c86e55dSMatthew Auld static void gen8_ggtt_insert_page(struct i915_address_space *vm, 2082c86e55dSMatthew Auld dma_addr_t addr, 2092c86e55dSMatthew Auld u64 offset, 2102c86e55dSMatthew Auld enum i915_cache_level level, 211e762bdf5SMatthew Auld u32 flags) 2122c86e55dSMatthew Auld { 2132c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2142c86e55dSMatthew Auld gen8_pte_t __iomem *pte = 2152c86e55dSMatthew Auld (gen8_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; 2162c86e55dSMatthew Auld 217e762bdf5SMatthew Auld gen8_set_pte(pte, gen8_ggtt_pte_encode(addr, level, flags)); 2182c86e55dSMatthew Auld 2192c86e55dSMatthew Auld ggtt->invalidate(ggtt); 2202c86e55dSMatthew Auld } 2212c86e55dSMatthew Auld 2222c86e55dSMatthew Auld static void gen8_ggtt_insert_entries(struct i915_address_space *vm, 2232c86e55dSMatthew Auld struct i915_vma *vma, 2242c86e55dSMatthew Auld enum i915_cache_level level, 2252c86e55dSMatthew Auld u32 flags) 2262c86e55dSMatthew Auld { 227e762bdf5SMatthew Auld const gen8_pte_t pte_encode = gen8_ggtt_pte_encode(0, level, flags); 2284d6c1859SChris Wilson struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2294d6c1859SChris Wilson gen8_pte_t __iomem *gte; 2304d6c1859SChris Wilson gen8_pte_t __iomem *end; 2314d6c1859SChris Wilson struct sgt_iter iter; 2322c86e55dSMatthew Auld dma_addr_t addr; 2332c86e55dSMatthew Auld 2342c86e55dSMatthew Auld /* 2352c86e55dSMatthew Auld * Note that we ignore PTE_READ_ONLY here. The caller must be careful 2362c86e55dSMatthew Auld * not to allow the user to override access to a read only page. 2372c86e55dSMatthew Auld */ 2382c86e55dSMatthew Auld 2394d6c1859SChris Wilson gte = (gen8_pte_t __iomem *)ggtt->gsm; 2404d6c1859SChris Wilson gte += vma->node.start / I915_GTT_PAGE_SIZE; 2414d6c1859SChris Wilson end = gte + vma->node.size / I915_GTT_PAGE_SIZE; 2424d6c1859SChris Wilson 2434d6c1859SChris Wilson for_each_sgt_daddr(addr, iter, vma->pages) 2444d6c1859SChris Wilson gen8_set_pte(gte++, pte_encode | addr); 2454d6c1859SChris Wilson GEM_BUG_ON(gte > end); 2464d6c1859SChris Wilson 2474d6c1859SChris Wilson /* Fill the allocated but "unused" space beyond the end of the buffer */ 2484d6c1859SChris Wilson while (gte < end) 24989351925SChris Wilson gen8_set_pte(gte++, vm->scratch[0]->encode); 2502c86e55dSMatthew Auld 2512c86e55dSMatthew Auld /* 2522c86e55dSMatthew Auld * We want to flush the TLBs only after we're certain all the PTE 2532c86e55dSMatthew Auld * updates have finished. 2542c86e55dSMatthew Auld */ 2552c86e55dSMatthew Auld ggtt->invalidate(ggtt); 2562c86e55dSMatthew Auld } 2572c86e55dSMatthew Auld 2582c86e55dSMatthew Auld static void gen6_ggtt_insert_page(struct i915_address_space *vm, 2592c86e55dSMatthew Auld dma_addr_t addr, 2602c86e55dSMatthew Auld u64 offset, 2612c86e55dSMatthew Auld enum i915_cache_level level, 2622c86e55dSMatthew Auld u32 flags) 2632c86e55dSMatthew Auld { 2642c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2652c86e55dSMatthew Auld gen6_pte_t __iomem *pte = 2662c86e55dSMatthew Auld (gen6_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; 2672c86e55dSMatthew Auld 2682c86e55dSMatthew Auld iowrite32(vm->pte_encode(addr, level, flags), pte); 2692c86e55dSMatthew Auld 2702c86e55dSMatthew Auld ggtt->invalidate(ggtt); 2712c86e55dSMatthew Auld } 2722c86e55dSMatthew Auld 2732c86e55dSMatthew Auld /* 2742c86e55dSMatthew Auld * Binds an object into the global gtt with the specified cache level. 2752c86e55dSMatthew Auld * The object will be accessible to the GPU via commands whose operands 2762c86e55dSMatthew Auld * reference offsets within the global GTT as well as accessible by the GPU 2772c86e55dSMatthew Auld * through the GMADR mapped BAR (i915->mm.gtt->gtt). 2782c86e55dSMatthew Auld */ 2792c86e55dSMatthew Auld static void gen6_ggtt_insert_entries(struct i915_address_space *vm, 2802c86e55dSMatthew Auld struct i915_vma *vma, 2812c86e55dSMatthew Auld enum i915_cache_level level, 2822c86e55dSMatthew Auld u32 flags) 2832c86e55dSMatthew Auld { 2842c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 2854d6c1859SChris Wilson gen6_pte_t __iomem *gte; 2864d6c1859SChris Wilson gen6_pte_t __iomem *end; 2872c86e55dSMatthew Auld struct sgt_iter iter; 2882c86e55dSMatthew Auld dma_addr_t addr; 2892c86e55dSMatthew Auld 2904d6c1859SChris Wilson gte = (gen6_pte_t __iomem *)ggtt->gsm; 2914d6c1859SChris Wilson gte += vma->node.start / I915_GTT_PAGE_SIZE; 2924d6c1859SChris Wilson end = gte + vma->node.size / I915_GTT_PAGE_SIZE; 2934d6c1859SChris Wilson 2942c86e55dSMatthew Auld for_each_sgt_daddr(addr, iter, vma->pages) 2954d6c1859SChris Wilson iowrite32(vm->pte_encode(addr, level, flags), gte++); 2964d6c1859SChris Wilson GEM_BUG_ON(gte > end); 2974d6c1859SChris Wilson 2984d6c1859SChris Wilson /* Fill the allocated but "unused" space beyond the end of the buffer */ 2994d6c1859SChris Wilson while (gte < end) 30089351925SChris Wilson iowrite32(vm->scratch[0]->encode, gte++); 3012c86e55dSMatthew Auld 3022c86e55dSMatthew Auld /* 3032c86e55dSMatthew Auld * We want to flush the TLBs only after we're certain all the PTE 3042c86e55dSMatthew Auld * updates have finished. 3052c86e55dSMatthew Auld */ 3062c86e55dSMatthew Auld ggtt->invalidate(ggtt); 3072c86e55dSMatthew Auld } 3082c86e55dSMatthew Auld 3092c86e55dSMatthew Auld static void nop_clear_range(struct i915_address_space *vm, 3102c86e55dSMatthew Auld u64 start, u64 length) 3112c86e55dSMatthew Auld { 3122c86e55dSMatthew Auld } 3132c86e55dSMatthew Auld 3142c86e55dSMatthew Auld static void gen8_ggtt_clear_range(struct i915_address_space *vm, 3152c86e55dSMatthew Auld u64 start, u64 length) 3162c86e55dSMatthew Auld { 3172c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 3182c86e55dSMatthew Auld unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 3192c86e55dSMatthew Auld unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 32089351925SChris Wilson const gen8_pte_t scratch_pte = vm->scratch[0]->encode; 3212c86e55dSMatthew Auld gen8_pte_t __iomem *gtt_base = 3222c86e55dSMatthew Auld (gen8_pte_t __iomem *)ggtt->gsm + first_entry; 3232c86e55dSMatthew Auld const int max_entries = ggtt_total_entries(ggtt) - first_entry; 3242c86e55dSMatthew Auld int i; 3252c86e55dSMatthew Auld 3262c86e55dSMatthew Auld if (WARN(num_entries > max_entries, 3272c86e55dSMatthew Auld "First entry = %d; Num entries = %d (max=%d)\n", 3282c86e55dSMatthew Auld first_entry, num_entries, max_entries)) 3292c86e55dSMatthew Auld num_entries = max_entries; 3302c86e55dSMatthew Auld 3312c86e55dSMatthew Auld for (i = 0; i < num_entries; i++) 3322c86e55dSMatthew Auld gen8_set_pte(>t_base[i], scratch_pte); 3332c86e55dSMatthew Auld } 3342c86e55dSMatthew Auld 3352c86e55dSMatthew Auld static void bxt_vtd_ggtt_wa(struct i915_address_space *vm) 3362c86e55dSMatthew Auld { 3372c86e55dSMatthew Auld /* 3382c86e55dSMatthew Auld * Make sure the internal GAM fifo has been cleared of all GTT 3392c86e55dSMatthew Auld * writes before exiting stop_machine(). This guarantees that 3402c86e55dSMatthew Auld * any aperture accesses waiting to start in another process 3412c86e55dSMatthew Auld * cannot back up behind the GTT writes causing a hang. 3422c86e55dSMatthew Auld * The register can be any arbitrary GAM register. 3432c86e55dSMatthew Auld */ 3442c86e55dSMatthew Auld intel_uncore_posting_read_fw(vm->gt->uncore, GFX_FLSH_CNTL_GEN6); 3452c86e55dSMatthew Auld } 3462c86e55dSMatthew Auld 3472c86e55dSMatthew Auld struct insert_page { 3482c86e55dSMatthew Auld struct i915_address_space *vm; 3492c86e55dSMatthew Auld dma_addr_t addr; 3502c86e55dSMatthew Auld u64 offset; 3512c86e55dSMatthew Auld enum i915_cache_level level; 3522c86e55dSMatthew Auld }; 3532c86e55dSMatthew Auld 3542c86e55dSMatthew Auld static int bxt_vtd_ggtt_insert_page__cb(void *_arg) 3552c86e55dSMatthew Auld { 3562c86e55dSMatthew Auld struct insert_page *arg = _arg; 3572c86e55dSMatthew Auld 3582c86e55dSMatthew Auld gen8_ggtt_insert_page(arg->vm, arg->addr, arg->offset, arg->level, 0); 3592c86e55dSMatthew Auld bxt_vtd_ggtt_wa(arg->vm); 3602c86e55dSMatthew Auld 3612c86e55dSMatthew Auld return 0; 3622c86e55dSMatthew Auld } 3632c86e55dSMatthew Auld 3642c86e55dSMatthew Auld static void bxt_vtd_ggtt_insert_page__BKL(struct i915_address_space *vm, 3652c86e55dSMatthew Auld dma_addr_t addr, 3662c86e55dSMatthew Auld u64 offset, 3672c86e55dSMatthew Auld enum i915_cache_level level, 3682c86e55dSMatthew Auld u32 unused) 3692c86e55dSMatthew Auld { 3702c86e55dSMatthew Auld struct insert_page arg = { vm, addr, offset, level }; 3712c86e55dSMatthew Auld 3722c86e55dSMatthew Auld stop_machine(bxt_vtd_ggtt_insert_page__cb, &arg, NULL); 3732c86e55dSMatthew Auld } 3742c86e55dSMatthew Auld 3752c86e55dSMatthew Auld struct insert_entries { 3762c86e55dSMatthew Auld struct i915_address_space *vm; 3772c86e55dSMatthew Auld struct i915_vma *vma; 3782c86e55dSMatthew Auld enum i915_cache_level level; 3792c86e55dSMatthew Auld u32 flags; 3802c86e55dSMatthew Auld }; 3812c86e55dSMatthew Auld 3822c86e55dSMatthew Auld static int bxt_vtd_ggtt_insert_entries__cb(void *_arg) 3832c86e55dSMatthew Auld { 3842c86e55dSMatthew Auld struct insert_entries *arg = _arg; 3852c86e55dSMatthew Auld 3862c86e55dSMatthew Auld gen8_ggtt_insert_entries(arg->vm, arg->vma, arg->level, arg->flags); 3872c86e55dSMatthew Auld bxt_vtd_ggtt_wa(arg->vm); 3882c86e55dSMatthew Auld 3892c86e55dSMatthew Auld return 0; 3902c86e55dSMatthew Auld } 3912c86e55dSMatthew Auld 3922c86e55dSMatthew Auld static void bxt_vtd_ggtt_insert_entries__BKL(struct i915_address_space *vm, 3932c86e55dSMatthew Auld struct i915_vma *vma, 3942c86e55dSMatthew Auld enum i915_cache_level level, 3952c86e55dSMatthew Auld u32 flags) 3962c86e55dSMatthew Auld { 3972c86e55dSMatthew Auld struct insert_entries arg = { vm, vma, level, flags }; 3982c86e55dSMatthew Auld 3992c86e55dSMatthew Auld stop_machine(bxt_vtd_ggtt_insert_entries__cb, &arg, NULL); 4002c86e55dSMatthew Auld } 4012c86e55dSMatthew Auld 4022c86e55dSMatthew Auld static void gen6_ggtt_clear_range(struct i915_address_space *vm, 4032c86e55dSMatthew Auld u64 start, u64 length) 4042c86e55dSMatthew Auld { 4052c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 4062c86e55dSMatthew Auld unsigned int first_entry = start / I915_GTT_PAGE_SIZE; 4072c86e55dSMatthew Auld unsigned int num_entries = length / I915_GTT_PAGE_SIZE; 4082c86e55dSMatthew Auld gen6_pte_t scratch_pte, __iomem *gtt_base = 4092c86e55dSMatthew Auld (gen6_pte_t __iomem *)ggtt->gsm + first_entry; 4102c86e55dSMatthew Auld const int max_entries = ggtt_total_entries(ggtt) - first_entry; 4112c86e55dSMatthew Auld int i; 4122c86e55dSMatthew Auld 4132c86e55dSMatthew Auld if (WARN(num_entries > max_entries, 4142c86e55dSMatthew Auld "First entry = %d; Num entries = %d (max=%d)\n", 4152c86e55dSMatthew Auld first_entry, num_entries, max_entries)) 4162c86e55dSMatthew Auld num_entries = max_entries; 4172c86e55dSMatthew Auld 41889351925SChris Wilson scratch_pte = vm->scratch[0]->encode; 4192c86e55dSMatthew Auld for (i = 0; i < num_entries; i++) 4202c86e55dSMatthew Auld iowrite32(scratch_pte, >t_base[i]); 4212c86e55dSMatthew Auld } 4222c86e55dSMatthew Auld 4232c86e55dSMatthew Auld static void i915_ggtt_insert_page(struct i915_address_space *vm, 4242c86e55dSMatthew Auld dma_addr_t addr, 4252c86e55dSMatthew Auld u64 offset, 4262c86e55dSMatthew Auld enum i915_cache_level cache_level, 4272c86e55dSMatthew Auld u32 unused) 4282c86e55dSMatthew Auld { 4292c86e55dSMatthew Auld unsigned int flags = (cache_level == I915_CACHE_NONE) ? 4302c86e55dSMatthew Auld AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; 4312c86e55dSMatthew Auld 4322c86e55dSMatthew Auld intel_gtt_insert_page(addr, offset >> PAGE_SHIFT, flags); 4332c86e55dSMatthew Auld } 4342c86e55dSMatthew Auld 4352c86e55dSMatthew Auld static void i915_ggtt_insert_entries(struct i915_address_space *vm, 4362c86e55dSMatthew Auld struct i915_vma *vma, 4372c86e55dSMatthew Auld enum i915_cache_level cache_level, 4382c86e55dSMatthew Auld u32 unused) 4392c86e55dSMatthew Auld { 4402c86e55dSMatthew Auld unsigned int flags = (cache_level == I915_CACHE_NONE) ? 4412c86e55dSMatthew Auld AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; 4422c86e55dSMatthew Auld 4432c86e55dSMatthew Auld intel_gtt_insert_sg_entries(vma->pages, vma->node.start >> PAGE_SHIFT, 4442c86e55dSMatthew Auld flags); 4452c86e55dSMatthew Auld } 4462c86e55dSMatthew Auld 4472c86e55dSMatthew Auld static void i915_ggtt_clear_range(struct i915_address_space *vm, 4482c86e55dSMatthew Auld u64 start, u64 length) 4492c86e55dSMatthew Auld { 4502c86e55dSMatthew Auld intel_gtt_clear_range(start >> PAGE_SHIFT, length >> PAGE_SHIFT); 4512c86e55dSMatthew Auld } 4522c86e55dSMatthew Auld 453cd0452aaSChris Wilson static void ggtt_bind_vma(struct i915_address_space *vm, 454cd0452aaSChris Wilson struct i915_vm_pt_stash *stash, 45512b07256SChris Wilson struct i915_vma *vma, 4562c86e55dSMatthew Auld enum i915_cache_level cache_level, 4572c86e55dSMatthew Auld u32 flags) 4582c86e55dSMatthew Auld { 4592c86e55dSMatthew Auld struct drm_i915_gem_object *obj = vma->obj; 4602c86e55dSMatthew Auld u32 pte_flags; 4612c86e55dSMatthew Auld 462bf0840cdSChris Wilson if (i915_vma_is_bound(vma, ~flags & I915_VMA_BIND_MASK)) 463cd0452aaSChris Wilson return; 464bf0840cdSChris Wilson 4652c86e55dSMatthew Auld /* Applicable to VLV (gen8+ do not support RO in the GGTT) */ 4662c86e55dSMatthew Auld pte_flags = 0; 4672c86e55dSMatthew Auld if (i915_gem_object_is_readonly(obj)) 4682c86e55dSMatthew Auld pte_flags |= PTE_READ_ONLY; 469e762bdf5SMatthew Auld if (i915_gem_object_is_lmem(obj)) 470e762bdf5SMatthew Auld pte_flags |= PTE_LM; 4712c86e55dSMatthew Auld 47212b07256SChris Wilson vm->insert_entries(vm, vma, cache_level, pte_flags); 4732c86e55dSMatthew Auld vma->page_sizes.gtt = I915_GTT_PAGE_SIZE; 4742c86e55dSMatthew Auld } 4752c86e55dSMatthew Auld 47612b07256SChris Wilson static void ggtt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma) 4772c86e55dSMatthew Auld { 47812b07256SChris Wilson vm->clear_range(vm, vma->node.start, vma->size); 4792c86e55dSMatthew Auld } 4802c86e55dSMatthew Auld 4812c86e55dSMatthew Auld static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt) 4822c86e55dSMatthew Auld { 4832c86e55dSMatthew Auld u64 size; 4842c86e55dSMatthew Auld int ret; 4852c86e55dSMatthew Auld 48634bbfde6SDaniele Ceraolo Spurio if (!intel_uc_uses_guc(&ggtt->vm.gt->uc)) 4872c86e55dSMatthew Auld return 0; 4882c86e55dSMatthew Auld 4892c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP); 4902c86e55dSMatthew Auld size = ggtt->vm.total - GUC_GGTT_TOP; 4912c86e55dSMatthew Auld 4922c86e55dSMatthew Auld ret = i915_gem_gtt_reserve(&ggtt->vm, &ggtt->uc_fw, size, 4932c86e55dSMatthew Auld GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE, 4942c86e55dSMatthew Auld PIN_NOEVICT); 4952c86e55dSMatthew Auld if (ret) 49652ce7074SWambui Karuga drm_dbg(&ggtt->vm.i915->drm, 49752ce7074SWambui Karuga "Failed to reserve top of GGTT for GuC\n"); 4982c86e55dSMatthew Auld 4992c86e55dSMatthew Auld return ret; 5002c86e55dSMatthew Auld } 5012c86e55dSMatthew Auld 5022c86e55dSMatthew Auld static void ggtt_release_guc_top(struct i915_ggtt *ggtt) 5032c86e55dSMatthew Auld { 5042c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->uc_fw)) 5052c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->uc_fw); 5062c86e55dSMatthew Auld } 5072c86e55dSMatthew Auld 5082c86e55dSMatthew Auld static void cleanup_init_ggtt(struct i915_ggtt *ggtt) 5092c86e55dSMatthew Auld { 5102c86e55dSMatthew Auld ggtt_release_guc_top(ggtt); 5112c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->error_capture)) 5122c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->error_capture); 513742379c0SChris Wilson mutex_destroy(&ggtt->error_mutex); 5142c86e55dSMatthew Auld } 5152c86e55dSMatthew Auld 5162c86e55dSMatthew Auld static int init_ggtt(struct i915_ggtt *ggtt) 5172c86e55dSMatthew Auld { 5182c86e55dSMatthew Auld /* 5192c86e55dSMatthew Auld * Let GEM Manage all of the aperture. 5202c86e55dSMatthew Auld * 5212c86e55dSMatthew Auld * However, leave one page at the end still bound to the scratch page. 5222c86e55dSMatthew Auld * There are a number of places where the hardware apparently prefetches 5232c86e55dSMatthew Auld * past the end of the object, and we've seen multiple hangs with the 5242c86e55dSMatthew Auld * GPU head pointer stuck in a batchbuffer bound at the last page of the 5252c86e55dSMatthew Auld * aperture. One page should be enough to keep any prefetching inside 5262c86e55dSMatthew Auld * of the aperture. 5272c86e55dSMatthew Auld */ 5282c86e55dSMatthew Auld unsigned long hole_start, hole_end; 5292c86e55dSMatthew Auld struct drm_mm_node *entry; 5302c86e55dSMatthew Auld int ret; 5312c86e55dSMatthew Auld 5322c86e55dSMatthew Auld /* 5332c86e55dSMatthew Auld * GuC requires all resources that we're sharing with it to be placed in 5342c86e55dSMatthew Auld * non-WOPCM memory. If GuC is not present or not in use we still need a 5352c86e55dSMatthew Auld * small bias as ring wraparound at offset 0 sometimes hangs. No idea 5362c86e55dSMatthew Auld * why. 5372c86e55dSMatthew Auld */ 5382c86e55dSMatthew Auld ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE, 5392c86e55dSMatthew Auld intel_wopcm_guc_size(&ggtt->vm.i915->wopcm)); 5402c86e55dSMatthew Auld 5412c86e55dSMatthew Auld ret = intel_vgt_balloon(ggtt); 5422c86e55dSMatthew Auld if (ret) 5432c86e55dSMatthew Auld return ret; 5442c86e55dSMatthew Auld 545742379c0SChris Wilson mutex_init(&ggtt->error_mutex); 5462c86e55dSMatthew Auld if (ggtt->mappable_end) { 547489140b5SChris Wilson /* 548489140b5SChris Wilson * Reserve a mappable slot for our lockless error capture. 549489140b5SChris Wilson * 550489140b5SChris Wilson * We strongly prefer taking address 0x0 in order to protect 551489140b5SChris Wilson * other critical buffers against accidental overwrites, 552489140b5SChris Wilson * as writing to address 0 is a very common mistake. 553489140b5SChris Wilson * 554489140b5SChris Wilson * Since 0 may already be in use by the system (e.g. the BIOS 555489140b5SChris Wilson * framebuffer), we let the reservation fail quietly and hope 556489140b5SChris Wilson * 0 remains reserved always. 557489140b5SChris Wilson * 558489140b5SChris Wilson * If we fail to reserve 0, and then fail to find any space 559489140b5SChris Wilson * for an error-capture, remain silent. We can afford not 560489140b5SChris Wilson * to reserve an error_capture node as we have fallback 561489140b5SChris Wilson * paths, and we trust that 0 will remain reserved. However, 562489140b5SChris Wilson * the only likely reason for failure to insert is a driver 563489140b5SChris Wilson * bug, which we expect to cause other failures... 564489140b5SChris Wilson */ 565489140b5SChris Wilson ggtt->error_capture.size = I915_GTT_PAGE_SIZE; 566489140b5SChris Wilson ggtt->error_capture.color = I915_COLOR_UNEVICTABLE; 567489140b5SChris Wilson if (drm_mm_reserve_node(&ggtt->vm.mm, &ggtt->error_capture)) 568489140b5SChris Wilson drm_mm_insert_node_in_range(&ggtt->vm.mm, 5692c86e55dSMatthew Auld &ggtt->error_capture, 570489140b5SChris Wilson ggtt->error_capture.size, 0, 571489140b5SChris Wilson ggtt->error_capture.color, 5722c86e55dSMatthew Auld 0, ggtt->mappable_end, 5732c86e55dSMatthew Auld DRM_MM_INSERT_LOW); 5742c86e55dSMatthew Auld } 575489140b5SChris Wilson if (drm_mm_node_allocated(&ggtt->error_capture)) 576489140b5SChris Wilson drm_dbg(&ggtt->vm.i915->drm, 577489140b5SChris Wilson "Reserved GGTT:[%llx, %llx] for use by error capture\n", 578489140b5SChris Wilson ggtt->error_capture.start, 579489140b5SChris Wilson ggtt->error_capture.start + ggtt->error_capture.size); 5802c86e55dSMatthew Auld 5812c86e55dSMatthew Auld /* 5822c86e55dSMatthew Auld * The upper portion of the GuC address space has a sizeable hole 5832c86e55dSMatthew Auld * (several MB) that is inaccessible by GuC. Reserve this range within 5842c86e55dSMatthew Auld * GGTT as it can comfortably hold GuC/HuC firmware images. 5852c86e55dSMatthew Auld */ 5862c86e55dSMatthew Auld ret = ggtt_reserve_guc_top(ggtt); 5872c86e55dSMatthew Auld if (ret) 5882c86e55dSMatthew Auld goto err; 5892c86e55dSMatthew Auld 5902c86e55dSMatthew Auld /* Clear any non-preallocated blocks */ 5912c86e55dSMatthew Auld drm_mm_for_each_hole(entry, &ggtt->vm.mm, hole_start, hole_end) { 592489140b5SChris Wilson drm_dbg(&ggtt->vm.i915->drm, 59352ce7074SWambui Karuga "clearing unused GTT space: [%lx, %lx]\n", 5942c86e55dSMatthew Auld hole_start, hole_end); 5952c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, hole_start, 5962c86e55dSMatthew Auld hole_end - hole_start); 5972c86e55dSMatthew Auld } 5982c86e55dSMatthew Auld 5992c86e55dSMatthew Auld /* And finally clear the reserved guard page */ 6002c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, ggtt->vm.total - PAGE_SIZE, PAGE_SIZE); 6012c86e55dSMatthew Auld 6022c86e55dSMatthew Auld return 0; 6032c86e55dSMatthew Auld 6042c86e55dSMatthew Auld err: 6052c86e55dSMatthew Auld cleanup_init_ggtt(ggtt); 6062c86e55dSMatthew Auld return ret; 6072c86e55dSMatthew Auld } 6082c86e55dSMatthew Auld 609cd0452aaSChris Wilson static void aliasing_gtt_bind_vma(struct i915_address_space *vm, 610cd0452aaSChris Wilson struct i915_vm_pt_stash *stash, 61112b07256SChris Wilson struct i915_vma *vma, 6122c86e55dSMatthew Auld enum i915_cache_level cache_level, 6132c86e55dSMatthew Auld u32 flags) 6142c86e55dSMatthew Auld { 6152c86e55dSMatthew Auld u32 pte_flags; 6162c86e55dSMatthew Auld 6172c86e55dSMatthew Auld /* Currently applicable only to VLV */ 6182c86e55dSMatthew Auld pte_flags = 0; 6192c86e55dSMatthew Auld if (i915_gem_object_is_readonly(vma->obj)) 6202c86e55dSMatthew Auld pte_flags |= PTE_READ_ONLY; 6212c86e55dSMatthew Auld 622cd0452aaSChris Wilson if (flags & I915_VMA_LOCAL_BIND) 623cd0452aaSChris Wilson ppgtt_bind_vma(&i915_vm_to_ggtt(vm)->alias->vm, 624cd0452aaSChris Wilson stash, vma, cache_level, flags); 6252c86e55dSMatthew Auld 626c0e60347SChris Wilson if (flags & I915_VMA_GLOBAL_BIND) 62712b07256SChris Wilson vm->insert_entries(vm, vma, cache_level, pte_flags); 6282c86e55dSMatthew Auld } 6292c86e55dSMatthew Auld 63012b07256SChris Wilson static void aliasing_gtt_unbind_vma(struct i915_address_space *vm, 63112b07256SChris Wilson struct i915_vma *vma) 6322c86e55dSMatthew Auld { 63312b07256SChris Wilson if (i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND)) 6342c86e55dSMatthew Auld vm->clear_range(vm, vma->node.start, vma->size); 6352c86e55dSMatthew Auld 63612b07256SChris Wilson if (i915_vma_is_bound(vma, I915_VMA_LOCAL_BIND)) 63712b07256SChris Wilson ppgtt_unbind_vma(&i915_vm_to_ggtt(vm)->alias->vm, vma); 6382c86e55dSMatthew Auld } 6392c86e55dSMatthew Auld 6402c86e55dSMatthew Auld static int init_aliasing_ppgtt(struct i915_ggtt *ggtt) 6412c86e55dSMatthew Auld { 642cd0452aaSChris Wilson struct i915_vm_pt_stash stash = {}; 6432c86e55dSMatthew Auld struct i915_ppgtt *ppgtt; 6442c86e55dSMatthew Auld int err; 6452c86e55dSMatthew Auld 6462c86e55dSMatthew Auld ppgtt = i915_ppgtt_create(ggtt->vm.gt); 6472c86e55dSMatthew Auld if (IS_ERR(ppgtt)) 6482c86e55dSMatthew Auld return PTR_ERR(ppgtt); 6492c86e55dSMatthew Auld 6502c86e55dSMatthew Auld if (GEM_WARN_ON(ppgtt->vm.total < ggtt->vm.total)) { 6512c86e55dSMatthew Auld err = -ENODEV; 6522c86e55dSMatthew Auld goto err_ppgtt; 6532c86e55dSMatthew Auld } 6542c86e55dSMatthew Auld 655cd0452aaSChris Wilson err = i915_vm_alloc_pt_stash(&ppgtt->vm, &stash, ggtt->vm.total); 656cd0452aaSChris Wilson if (err) 657cd0452aaSChris Wilson goto err_ppgtt; 658cd0452aaSChris Wilson 65926ad4f8bSMaarten Lankhorst i915_gem_object_lock(ppgtt->vm.scratch[0], NULL); 660529b9ec8SMatthew Auld err = i915_vm_map_pt_stash(&ppgtt->vm, &stash); 66126ad4f8bSMaarten Lankhorst i915_gem_object_unlock(ppgtt->vm.scratch[0]); 66289351925SChris Wilson if (err) 66389351925SChris Wilson goto err_stash; 66489351925SChris Wilson 6652c86e55dSMatthew Auld /* 6662c86e55dSMatthew Auld * Note we only pre-allocate as far as the end of the global 6672c86e55dSMatthew Auld * GTT. On 48b / 4-level page-tables, the difference is very, 6682c86e55dSMatthew Auld * very significant! We have to preallocate as GVT/vgpu does 6692c86e55dSMatthew Auld * not like the page directory disappearing. 6702c86e55dSMatthew Auld */ 671cd0452aaSChris Wilson ppgtt->vm.allocate_va_range(&ppgtt->vm, &stash, 0, ggtt->vm.total); 6722c86e55dSMatthew Auld 6732c86e55dSMatthew Auld ggtt->alias = ppgtt; 6742c86e55dSMatthew Auld ggtt->vm.bind_async_flags |= ppgtt->vm.bind_async_flags; 6752c86e55dSMatthew Auld 6762c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.vma_ops.bind_vma != ggtt_bind_vma); 6772c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = aliasing_gtt_bind_vma; 6782c86e55dSMatthew Auld 6792c86e55dSMatthew Auld GEM_BUG_ON(ggtt->vm.vma_ops.unbind_vma != ggtt_unbind_vma); 6802c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = aliasing_gtt_unbind_vma; 6812c86e55dSMatthew Auld 682cd0452aaSChris Wilson i915_vm_free_pt_stash(&ppgtt->vm, &stash); 6832c86e55dSMatthew Auld return 0; 6842c86e55dSMatthew Auld 68589351925SChris Wilson err_stash: 68689351925SChris Wilson i915_vm_free_pt_stash(&ppgtt->vm, &stash); 6872c86e55dSMatthew Auld err_ppgtt: 6882c86e55dSMatthew Auld i915_vm_put(&ppgtt->vm); 6892c86e55dSMatthew Auld return err; 6902c86e55dSMatthew Auld } 6912c86e55dSMatthew Auld 6922c86e55dSMatthew Auld static void fini_aliasing_ppgtt(struct i915_ggtt *ggtt) 6932c86e55dSMatthew Auld { 6942c86e55dSMatthew Auld struct i915_ppgtt *ppgtt; 6952c86e55dSMatthew Auld 6962c86e55dSMatthew Auld ppgtt = fetch_and_zero(&ggtt->alias); 6972c86e55dSMatthew Auld if (!ppgtt) 6982c86e55dSMatthew Auld return; 6992c86e55dSMatthew Auld 7002c86e55dSMatthew Auld i915_vm_put(&ppgtt->vm); 7012c86e55dSMatthew Auld 7022c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 7032c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 7042c86e55dSMatthew Auld } 7052c86e55dSMatthew Auld 7062c86e55dSMatthew Auld int i915_init_ggtt(struct drm_i915_private *i915) 7072c86e55dSMatthew Auld { 7082c86e55dSMatthew Auld int ret; 7092c86e55dSMatthew Auld 7102c86e55dSMatthew Auld ret = init_ggtt(&i915->ggtt); 7112c86e55dSMatthew Auld if (ret) 7122c86e55dSMatthew Auld return ret; 7132c86e55dSMatthew Auld 7142c86e55dSMatthew Auld if (INTEL_PPGTT(i915) == INTEL_PPGTT_ALIASING) { 7152c86e55dSMatthew Auld ret = init_aliasing_ppgtt(&i915->ggtt); 7162c86e55dSMatthew Auld if (ret) 7172c86e55dSMatthew Auld cleanup_init_ggtt(&i915->ggtt); 7182c86e55dSMatthew Auld } 7192c86e55dSMatthew Auld 7202c86e55dSMatthew Auld return 0; 7212c86e55dSMatthew Auld } 7222c86e55dSMatthew Auld 7232c86e55dSMatthew Auld static void ggtt_cleanup_hw(struct i915_ggtt *ggtt) 7242c86e55dSMatthew Auld { 7252c86e55dSMatthew Auld struct i915_vma *vma, *vn; 7262c86e55dSMatthew Auld 7272c86e55dSMatthew Auld atomic_set(&ggtt->vm.open, 0); 7282c86e55dSMatthew Auld 7292c86e55dSMatthew Auld rcu_barrier(); /* flush the RCU'ed__i915_vm_release */ 7302c86e55dSMatthew Auld flush_workqueue(ggtt->vm.i915->wq); 7312c86e55dSMatthew Auld 7322c86e55dSMatthew Auld mutex_lock(&ggtt->vm.mutex); 7332c86e55dSMatthew Auld 7342c86e55dSMatthew Auld list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) 7352c86e55dSMatthew Auld WARN_ON(__i915_vma_unbind(vma)); 7362c86e55dSMatthew Auld 7372c86e55dSMatthew Auld if (drm_mm_node_allocated(&ggtt->error_capture)) 7382c86e55dSMatthew Auld drm_mm_remove_node(&ggtt->error_capture); 739742379c0SChris Wilson mutex_destroy(&ggtt->error_mutex); 7402c86e55dSMatthew Auld 7412c86e55dSMatthew Auld ggtt_release_guc_top(ggtt); 7422c86e55dSMatthew Auld intel_vgt_deballoon(ggtt); 7432c86e55dSMatthew Auld 7442c86e55dSMatthew Auld ggtt->vm.cleanup(&ggtt->vm); 7452c86e55dSMatthew Auld 7462c86e55dSMatthew Auld mutex_unlock(&ggtt->vm.mutex); 7472c86e55dSMatthew Auld i915_address_space_fini(&ggtt->vm); 74826ad4f8bSMaarten Lankhorst dma_resv_fini(&ggtt->vm.resv); 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 7702c86e55dSMatthew Auld static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) 7712c86e55dSMatthew Auld { 7722c86e55dSMatthew Auld snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT; 7732c86e55dSMatthew Auld snb_gmch_ctl &= SNB_GMCH_GGMS_MASK; 7742c86e55dSMatthew Auld return snb_gmch_ctl << 20; 7752c86e55dSMatthew Auld } 7762c86e55dSMatthew Auld 7772c86e55dSMatthew Auld static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl) 7782c86e55dSMatthew Auld { 7792c86e55dSMatthew Auld bdw_gmch_ctl >>= BDW_GMCH_GGMS_SHIFT; 7802c86e55dSMatthew Auld bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK; 7812c86e55dSMatthew Auld if (bdw_gmch_ctl) 7822c86e55dSMatthew Auld bdw_gmch_ctl = 1 << bdw_gmch_ctl; 7832c86e55dSMatthew Auld 7842c86e55dSMatthew Auld #ifdef CONFIG_X86_32 7852c86e55dSMatthew Auld /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * I915_GTT_PAGE_SIZE */ 7862c86e55dSMatthew Auld if (bdw_gmch_ctl > 4) 7872c86e55dSMatthew Auld bdw_gmch_ctl = 4; 7882c86e55dSMatthew Auld #endif 7892c86e55dSMatthew Auld 7902c86e55dSMatthew Auld return bdw_gmch_ctl << 20; 7912c86e55dSMatthew Auld } 7922c86e55dSMatthew Auld 7932c86e55dSMatthew Auld static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl) 7942c86e55dSMatthew Auld { 7952c86e55dSMatthew Auld gmch_ctrl >>= SNB_GMCH_GGMS_SHIFT; 7962c86e55dSMatthew Auld gmch_ctrl &= SNB_GMCH_GGMS_MASK; 7972c86e55dSMatthew Auld 7982c86e55dSMatthew Auld if (gmch_ctrl) 7992c86e55dSMatthew Auld return 1 << (20 + gmch_ctrl); 8002c86e55dSMatthew Auld 8012c86e55dSMatthew Auld return 0; 8022c86e55dSMatthew Auld } 8032c86e55dSMatthew Auld 8042c86e55dSMatthew Auld static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) 8052c86e55dSMatthew Auld { 8062c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 807e322551fSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 8082c86e55dSMatthew Auld phys_addr_t phys_addr; 809e762bdf5SMatthew Auld u32 pte_flags; 8102c86e55dSMatthew Auld int ret; 8112c86e55dSMatthew Auld 8122c86e55dSMatthew Auld /* For Modern GENs the PTEs and register space are split in the BAR */ 8132c86e55dSMatthew Auld phys_addr = pci_resource_start(pdev, 0) + pci_resource_len(pdev, 0) / 2; 8142c86e55dSMatthew Auld 8152c86e55dSMatthew Auld /* 8162c86e55dSMatthew Auld * On BXT+/CNL+ writes larger than 64 bit to the GTT pagetable range 8172c86e55dSMatthew Auld * will be dropped. For WC mappings in general we have 64 byte burst 8182c86e55dSMatthew Auld * writes when the WC buffer is flushed, so we can't use it, but have to 8192c86e55dSMatthew Auld * resort to an uncached mapping. The WC issue is easily caught by the 8202c86e55dSMatthew Auld * readback check when writing GTT PTE entries. 8212c86e55dSMatthew Auld */ 8222c86e55dSMatthew Auld if (IS_GEN9_LP(i915) || INTEL_GEN(i915) >= 10) 8239f68e365SLinus Torvalds ggtt->gsm = ioremap(phys_addr, size); 8242c86e55dSMatthew Auld else 8252c86e55dSMatthew Auld ggtt->gsm = ioremap_wc(phys_addr, size); 8262c86e55dSMatthew Auld if (!ggtt->gsm) { 82736034c95SWambui Karuga drm_err(&i915->drm, "Failed to map the ggtt page table\n"); 8282c86e55dSMatthew Auld return -ENOMEM; 8292c86e55dSMatthew Auld } 8302c86e55dSMatthew Auld 83189351925SChris Wilson ret = setup_scratch_page(&ggtt->vm); 8322c86e55dSMatthew Auld if (ret) { 83336034c95SWambui Karuga drm_err(&i915->drm, "Scratch setup failed\n"); 8342c86e55dSMatthew Auld /* iounmap will also get called at remove, but meh */ 8352c86e55dSMatthew Auld iounmap(ggtt->gsm); 8362c86e55dSMatthew Auld return ret; 8372c86e55dSMatthew Auld } 8382c86e55dSMatthew Auld 839e762bdf5SMatthew Auld pte_flags = 0; 840e762bdf5SMatthew Auld if (i915_gem_object_is_lmem(ggtt->vm.scratch[0])) 841e762bdf5SMatthew Auld pte_flags |= PTE_LM; 842e762bdf5SMatthew Auld 84389351925SChris Wilson ggtt->vm.scratch[0]->encode = 84489351925SChris Wilson ggtt->vm.pte_encode(px_dma(ggtt->vm.scratch[0]), 845e762bdf5SMatthew Auld I915_CACHE_NONE, pte_flags); 8462c86e55dSMatthew Auld 8472c86e55dSMatthew Auld return 0; 8482c86e55dSMatthew Auld } 8492c86e55dSMatthew Auld 8502c86e55dSMatthew Auld int ggtt_set_pages(struct i915_vma *vma) 8512c86e55dSMatthew Auld { 8522c86e55dSMatthew Auld int ret; 8532c86e55dSMatthew Auld 8542c86e55dSMatthew Auld GEM_BUG_ON(vma->pages); 8552c86e55dSMatthew Auld 8562c86e55dSMatthew Auld ret = i915_get_ggtt_vma_pages(vma); 8572c86e55dSMatthew Auld if (ret) 8582c86e55dSMatthew Auld return ret; 8592c86e55dSMatthew Auld 8602c86e55dSMatthew Auld vma->page_sizes = vma->obj->mm.page_sizes; 8612c86e55dSMatthew Auld 8622c86e55dSMatthew Auld return 0; 8632c86e55dSMatthew Auld } 8642c86e55dSMatthew Auld 8652c86e55dSMatthew Auld static void gen6_gmch_remove(struct i915_address_space *vm) 8662c86e55dSMatthew Auld { 8672c86e55dSMatthew Auld struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); 8682c86e55dSMatthew Auld 8692c86e55dSMatthew Auld iounmap(ggtt->gsm); 87089351925SChris Wilson free_scratch(vm); 8712c86e55dSMatthew Auld } 8722c86e55dSMatthew Auld 8732c86e55dSMatthew Auld static struct resource pci_resource(struct pci_dev *pdev, int bar) 8742c86e55dSMatthew Auld { 8752c86e55dSMatthew Auld return (struct resource)DEFINE_RES_MEM(pci_resource_start(pdev, bar), 8762c86e55dSMatthew Auld pci_resource_len(pdev, bar)); 8772c86e55dSMatthew Auld } 8782c86e55dSMatthew Auld 8792c86e55dSMatthew Auld static int gen8_gmch_probe(struct i915_ggtt *ggtt) 8802c86e55dSMatthew Auld { 8812c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 882e322551fSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 8832c86e55dSMatthew Auld unsigned int size; 8842c86e55dSMatthew Auld u16 snb_gmch_ctl; 8852c86e55dSMatthew Auld 8862c86e55dSMatthew Auld /* TODO: We're not aware of mappable constraints on gen8 yet */ 887b1e93a85SLucas De Marchi if (!HAS_LMEM(i915)) { 8882c86e55dSMatthew Auld ggtt->gmadr = pci_resource(pdev, 2); 8892c86e55dSMatthew Auld ggtt->mappable_end = resource_size(&ggtt->gmadr); 8902c86e55dSMatthew Auld } 8912c86e55dSMatthew Auld 8922c86e55dSMatthew Auld pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); 8932c86e55dSMatthew Auld if (IS_CHERRYVIEW(i915)) 8942c86e55dSMatthew Auld size = chv_get_total_gtt_size(snb_gmch_ctl); 8952c86e55dSMatthew Auld else 8962c86e55dSMatthew Auld size = gen8_get_total_gtt_size(snb_gmch_ctl); 8972c86e55dSMatthew Auld 89889351925SChris Wilson ggtt->vm.alloc_pt_dma = alloc_pt_dma; 89989351925SChris Wilson 9002c86e55dSMatthew Auld ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; 9012c86e55dSMatthew Auld ggtt->vm.cleanup = gen6_gmch_remove; 9022c86e55dSMatthew Auld ggtt->vm.insert_page = gen8_ggtt_insert_page; 9032c86e55dSMatthew Auld ggtt->vm.clear_range = nop_clear_range; 9042c86e55dSMatthew Auld if (intel_scanout_needs_vtd_wa(i915)) 9052c86e55dSMatthew Auld ggtt->vm.clear_range = gen8_ggtt_clear_range; 9062c86e55dSMatthew Auld 9072c86e55dSMatthew Auld ggtt->vm.insert_entries = gen8_ggtt_insert_entries; 9082c86e55dSMatthew Auld 909*bc6f80ccSMaarten Lankhorst /* 910*bc6f80ccSMaarten Lankhorst * Serialize GTT updates with aperture access on BXT if VT-d is on, 911*bc6f80ccSMaarten Lankhorst * and always on CHV. 912*bc6f80ccSMaarten Lankhorst */ 913*bc6f80ccSMaarten Lankhorst if (intel_vm_no_concurrent_access_wa(i915)) { 9142c86e55dSMatthew Auld ggtt->vm.insert_entries = bxt_vtd_ggtt_insert_entries__BKL; 9152c86e55dSMatthew Auld ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL; 916a34f61d2SChris Wilson ggtt->vm.bind_async_flags = 917a34f61d2SChris Wilson I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND; 9182c86e55dSMatthew Auld } 9192c86e55dSMatthew Auld 9202c86e55dSMatthew Auld ggtt->invalidate = gen8_ggtt_invalidate; 9212c86e55dSMatthew Auld 9222c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 9232c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 9242c86e55dSMatthew Auld ggtt->vm.vma_ops.set_pages = ggtt_set_pages; 9252c86e55dSMatthew Auld ggtt->vm.vma_ops.clear_pages = clear_pages; 9262c86e55dSMatthew Auld 92769edc390SDaniele Ceraolo Spurio ggtt->vm.pte_encode = gen8_ggtt_pte_encode; 9282c86e55dSMatthew Auld 9292c86e55dSMatthew Auld setup_private_pat(ggtt->vm.gt->uncore); 9302c86e55dSMatthew Auld 9312c86e55dSMatthew Auld return ggtt_probe_common(ggtt, size); 9322c86e55dSMatthew Auld } 9332c86e55dSMatthew Auld 9342c86e55dSMatthew Auld static u64 snb_pte_encode(dma_addr_t addr, 9352c86e55dSMatthew Auld enum i915_cache_level level, 9362c86e55dSMatthew Auld u32 flags) 9372c86e55dSMatthew Auld { 9382c86e55dSMatthew Auld gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9392c86e55dSMatthew Auld 9402c86e55dSMatthew Auld switch (level) { 9412c86e55dSMatthew Auld case I915_CACHE_L3_LLC: 9422c86e55dSMatthew Auld case I915_CACHE_LLC: 9432c86e55dSMatthew Auld pte |= GEN6_PTE_CACHE_LLC; 9442c86e55dSMatthew Auld break; 9452c86e55dSMatthew Auld case I915_CACHE_NONE: 9462c86e55dSMatthew Auld pte |= GEN6_PTE_UNCACHED; 9472c86e55dSMatthew Auld break; 9482c86e55dSMatthew Auld default: 9492c86e55dSMatthew Auld MISSING_CASE(level); 9502c86e55dSMatthew Auld } 9512c86e55dSMatthew Auld 9522c86e55dSMatthew Auld return pte; 9532c86e55dSMatthew Auld } 9542c86e55dSMatthew Auld 9552c86e55dSMatthew Auld static u64 ivb_pte_encode(dma_addr_t addr, 9562c86e55dSMatthew Auld enum i915_cache_level level, 9572c86e55dSMatthew Auld u32 flags) 9582c86e55dSMatthew Auld { 9592c86e55dSMatthew Auld gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9602c86e55dSMatthew Auld 9612c86e55dSMatthew Auld switch (level) { 9622c86e55dSMatthew Auld case I915_CACHE_L3_LLC: 9632c86e55dSMatthew Auld pte |= GEN7_PTE_CACHE_L3_LLC; 9642c86e55dSMatthew Auld break; 9652c86e55dSMatthew Auld case I915_CACHE_LLC: 9662c86e55dSMatthew Auld pte |= GEN6_PTE_CACHE_LLC; 9672c86e55dSMatthew Auld break; 9682c86e55dSMatthew Auld case I915_CACHE_NONE: 9692c86e55dSMatthew Auld pte |= GEN6_PTE_UNCACHED; 9702c86e55dSMatthew Auld break; 9712c86e55dSMatthew Auld default: 9722c86e55dSMatthew Auld MISSING_CASE(level); 9732c86e55dSMatthew Auld } 9742c86e55dSMatthew Auld 9752c86e55dSMatthew Auld return pte; 9762c86e55dSMatthew Auld } 9772c86e55dSMatthew Auld 9782c86e55dSMatthew Auld static u64 byt_pte_encode(dma_addr_t addr, 9792c86e55dSMatthew Auld enum i915_cache_level level, 9802c86e55dSMatthew Auld u32 flags) 9812c86e55dSMatthew Auld { 9822c86e55dSMatthew Auld gen6_pte_t pte = GEN6_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9832c86e55dSMatthew Auld 9842c86e55dSMatthew Auld if (!(flags & PTE_READ_ONLY)) 9852c86e55dSMatthew Auld pte |= BYT_PTE_WRITEABLE; 9862c86e55dSMatthew Auld 9872c86e55dSMatthew Auld if (level != I915_CACHE_NONE) 9882c86e55dSMatthew Auld pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES; 9892c86e55dSMatthew Auld 9902c86e55dSMatthew Auld return pte; 9912c86e55dSMatthew Auld } 9922c86e55dSMatthew Auld 9932c86e55dSMatthew Auld static u64 hsw_pte_encode(dma_addr_t addr, 9942c86e55dSMatthew Auld enum i915_cache_level level, 9952c86e55dSMatthew Auld u32 flags) 9962c86e55dSMatthew Auld { 9972c86e55dSMatthew Auld gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 9982c86e55dSMatthew Auld 9992c86e55dSMatthew Auld if (level != I915_CACHE_NONE) 10002c86e55dSMatthew Auld pte |= HSW_WB_LLC_AGE3; 10012c86e55dSMatthew Auld 10022c86e55dSMatthew Auld return pte; 10032c86e55dSMatthew Auld } 10042c86e55dSMatthew Auld 10052c86e55dSMatthew Auld static u64 iris_pte_encode(dma_addr_t addr, 10062c86e55dSMatthew Auld enum i915_cache_level level, 10072c86e55dSMatthew Auld u32 flags) 10082c86e55dSMatthew Auld { 10092c86e55dSMatthew Auld gen6_pte_t pte = HSW_PTE_ADDR_ENCODE(addr) | GEN6_PTE_VALID; 10102c86e55dSMatthew Auld 10112c86e55dSMatthew Auld switch (level) { 10122c86e55dSMatthew Auld case I915_CACHE_NONE: 10132c86e55dSMatthew Auld break; 10142c86e55dSMatthew Auld case I915_CACHE_WT: 10152c86e55dSMatthew Auld pte |= HSW_WT_ELLC_LLC_AGE3; 10162c86e55dSMatthew Auld break; 10172c86e55dSMatthew Auld default: 10182c86e55dSMatthew Auld pte |= HSW_WB_ELLC_LLC_AGE3; 10192c86e55dSMatthew Auld break; 10202c86e55dSMatthew Auld } 10212c86e55dSMatthew Auld 10222c86e55dSMatthew Auld return pte; 10232c86e55dSMatthew Auld } 10242c86e55dSMatthew Auld 10252c86e55dSMatthew Auld static int gen6_gmch_probe(struct i915_ggtt *ggtt) 10262c86e55dSMatthew Auld { 10272c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 1028e322551fSThomas Zimmermann struct pci_dev *pdev = to_pci_dev(i915->drm.dev); 10292c86e55dSMatthew Auld unsigned int size; 10302c86e55dSMatthew Auld u16 snb_gmch_ctl; 10312c86e55dSMatthew Auld 10322c86e55dSMatthew Auld ggtt->gmadr = pci_resource(pdev, 2); 10332c86e55dSMatthew Auld ggtt->mappable_end = resource_size(&ggtt->gmadr); 10342c86e55dSMatthew Auld 10352c86e55dSMatthew Auld /* 10362c86e55dSMatthew Auld * 64/512MB is the current min/max we actually know of, but this is 10372c86e55dSMatthew Auld * just a coarse sanity check. 10382c86e55dSMatthew Auld */ 10392c86e55dSMatthew Auld if (ggtt->mappable_end < (64<<20) || ggtt->mappable_end > (512<<20)) { 104036034c95SWambui Karuga drm_err(&i915->drm, "Unknown GMADR size (%pa)\n", 104136034c95SWambui Karuga &ggtt->mappable_end); 10422c86e55dSMatthew Auld return -ENXIO; 10432c86e55dSMatthew Auld } 10442c86e55dSMatthew Auld 10452c86e55dSMatthew Auld pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); 10462c86e55dSMatthew Auld 10472c86e55dSMatthew Auld size = gen6_get_total_gtt_size(snb_gmch_ctl); 10482c86e55dSMatthew Auld ggtt->vm.total = (size / sizeof(gen6_pte_t)) * I915_GTT_PAGE_SIZE; 10492c86e55dSMatthew Auld 105089351925SChris Wilson ggtt->vm.alloc_pt_dma = alloc_pt_dma; 105189351925SChris Wilson 10522c86e55dSMatthew Auld ggtt->vm.clear_range = nop_clear_range; 10532c86e55dSMatthew Auld if (!HAS_FULL_PPGTT(i915) || intel_scanout_needs_vtd_wa(i915)) 10542c86e55dSMatthew Auld ggtt->vm.clear_range = gen6_ggtt_clear_range; 10552c86e55dSMatthew Auld ggtt->vm.insert_page = gen6_ggtt_insert_page; 10562c86e55dSMatthew Auld ggtt->vm.insert_entries = gen6_ggtt_insert_entries; 10572c86e55dSMatthew Auld ggtt->vm.cleanup = gen6_gmch_remove; 10582c86e55dSMatthew Auld 10592c86e55dSMatthew Auld ggtt->invalidate = gen6_ggtt_invalidate; 10602c86e55dSMatthew Auld 10612c86e55dSMatthew Auld if (HAS_EDRAM(i915)) 10622c86e55dSMatthew Auld ggtt->vm.pte_encode = iris_pte_encode; 10632c86e55dSMatthew Auld else if (IS_HASWELL(i915)) 10642c86e55dSMatthew Auld ggtt->vm.pte_encode = hsw_pte_encode; 10652c86e55dSMatthew Auld else if (IS_VALLEYVIEW(i915)) 10662c86e55dSMatthew Auld ggtt->vm.pte_encode = byt_pte_encode; 10672c86e55dSMatthew Auld else if (INTEL_GEN(i915) >= 7) 10682c86e55dSMatthew Auld ggtt->vm.pte_encode = ivb_pte_encode; 10692c86e55dSMatthew Auld else 10702c86e55dSMatthew Auld ggtt->vm.pte_encode = snb_pte_encode; 10712c86e55dSMatthew Auld 10722c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 10732c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 10742c86e55dSMatthew Auld ggtt->vm.vma_ops.set_pages = ggtt_set_pages; 10752c86e55dSMatthew Auld ggtt->vm.vma_ops.clear_pages = clear_pages; 10762c86e55dSMatthew Auld 10772c86e55dSMatthew Auld return ggtt_probe_common(ggtt, size); 10782c86e55dSMatthew Auld } 10792c86e55dSMatthew Auld 10802c86e55dSMatthew Auld static void i915_gmch_remove(struct i915_address_space *vm) 10812c86e55dSMatthew Auld { 10822c86e55dSMatthew Auld intel_gmch_remove(); 10832c86e55dSMatthew Auld } 10842c86e55dSMatthew Auld 10852c86e55dSMatthew Auld static int i915_gmch_probe(struct i915_ggtt *ggtt) 10862c86e55dSMatthew Auld { 10872c86e55dSMatthew Auld struct drm_i915_private *i915 = ggtt->vm.i915; 10882c86e55dSMatthew Auld phys_addr_t gmadr_base; 10892c86e55dSMatthew Auld int ret; 10902c86e55dSMatthew Auld 1091e322551fSThomas Zimmermann ret = intel_gmch_probe(i915->bridge_dev, to_pci_dev(i915->drm.dev), NULL); 10922c86e55dSMatthew Auld if (!ret) { 109336034c95SWambui Karuga drm_err(&i915->drm, "failed to set up gmch\n"); 10942c86e55dSMatthew Auld return -EIO; 10952c86e55dSMatthew Auld } 10962c86e55dSMatthew Auld 10972c86e55dSMatthew Auld intel_gtt_get(&ggtt->vm.total, &gmadr_base, &ggtt->mappable_end); 10982c86e55dSMatthew Auld 10992c86e55dSMatthew Auld ggtt->gmadr = 11002c86e55dSMatthew Auld (struct resource)DEFINE_RES_MEM(gmadr_base, ggtt->mappable_end); 11012c86e55dSMatthew Auld 110289351925SChris Wilson ggtt->vm.alloc_pt_dma = alloc_pt_dma; 110389351925SChris Wilson 110484361529SChris Wilson if (needs_idle_maps(i915)) { 110584361529SChris Wilson drm_notice(&i915->drm, 110684361529SChris Wilson "Flushing DMA requests before IOMMU unmaps; performance may be degraded\n"); 110784361529SChris Wilson ggtt->do_idle_maps = true; 110884361529SChris Wilson } 110984361529SChris Wilson 11102c86e55dSMatthew Auld ggtt->vm.insert_page = i915_ggtt_insert_page; 11112c86e55dSMatthew Auld ggtt->vm.insert_entries = i915_ggtt_insert_entries; 11122c86e55dSMatthew Auld ggtt->vm.clear_range = i915_ggtt_clear_range; 11132c86e55dSMatthew Auld ggtt->vm.cleanup = i915_gmch_remove; 11142c86e55dSMatthew Auld 11152c86e55dSMatthew Auld ggtt->invalidate = gmch_ggtt_invalidate; 11162c86e55dSMatthew Auld 11172c86e55dSMatthew Auld ggtt->vm.vma_ops.bind_vma = ggtt_bind_vma; 11182c86e55dSMatthew Auld ggtt->vm.vma_ops.unbind_vma = ggtt_unbind_vma; 11192c86e55dSMatthew Auld ggtt->vm.vma_ops.set_pages = ggtt_set_pages; 11202c86e55dSMatthew Auld ggtt->vm.vma_ops.clear_pages = clear_pages; 11212c86e55dSMatthew Auld 11222c86e55dSMatthew Auld if (unlikely(ggtt->do_idle_maps)) 1123dc483ba5SJani Nikula drm_notice(&i915->drm, 11242c86e55dSMatthew Auld "Applying Ironlake quirks for intel_iommu\n"); 11252c86e55dSMatthew Auld 11262c86e55dSMatthew Auld return 0; 11272c86e55dSMatthew Auld } 11282c86e55dSMatthew Auld 11292c86e55dSMatthew Auld static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt) 11302c86e55dSMatthew Auld { 11312c86e55dSMatthew Auld struct drm_i915_private *i915 = gt->i915; 11322c86e55dSMatthew Auld int ret; 11332c86e55dSMatthew Auld 11342c86e55dSMatthew Auld ggtt->vm.gt = gt; 11352c86e55dSMatthew Auld ggtt->vm.i915 = i915; 1136e322551fSThomas Zimmermann ggtt->vm.dma = i915->drm.dev; 113726ad4f8bSMaarten Lankhorst dma_resv_init(&ggtt->vm.resv); 11382c86e55dSMatthew Auld 11392c86e55dSMatthew Auld if (INTEL_GEN(i915) <= 5) 11402c86e55dSMatthew Auld ret = i915_gmch_probe(ggtt); 11412c86e55dSMatthew Auld else if (INTEL_GEN(i915) < 8) 11422c86e55dSMatthew Auld ret = gen6_gmch_probe(ggtt); 11432c86e55dSMatthew Auld else 11442c86e55dSMatthew Auld ret = gen8_gmch_probe(ggtt); 114526ad4f8bSMaarten Lankhorst if (ret) { 114626ad4f8bSMaarten Lankhorst dma_resv_fini(&ggtt->vm.resv); 11472c86e55dSMatthew Auld return ret; 114826ad4f8bSMaarten Lankhorst } 11492c86e55dSMatthew Auld 11502c86e55dSMatthew Auld if ((ggtt->vm.total - 1) >> 32) { 115136034c95SWambui Karuga drm_err(&i915->drm, 115236034c95SWambui Karuga "We never expected a Global GTT with more than 32bits" 11532c86e55dSMatthew Auld " of address space! Found %lldM!\n", 11542c86e55dSMatthew Auld ggtt->vm.total >> 20); 11552c86e55dSMatthew Auld ggtt->vm.total = 1ULL << 32; 11562c86e55dSMatthew Auld ggtt->mappable_end = 11572c86e55dSMatthew Auld min_t(u64, ggtt->mappable_end, ggtt->vm.total); 11582c86e55dSMatthew Auld } 11592c86e55dSMatthew Auld 11602c86e55dSMatthew Auld if (ggtt->mappable_end > ggtt->vm.total) { 116136034c95SWambui Karuga drm_err(&i915->drm, 116236034c95SWambui Karuga "mappable aperture extends past end of GGTT," 11632c86e55dSMatthew Auld " aperture=%pa, total=%llx\n", 11642c86e55dSMatthew Auld &ggtt->mappable_end, ggtt->vm.total); 11652c86e55dSMatthew Auld ggtt->mappable_end = ggtt->vm.total; 11662c86e55dSMatthew Auld } 11672c86e55dSMatthew Auld 11682c86e55dSMatthew Auld /* GMADR is the PCI mmio aperture into the global GTT. */ 116936034c95SWambui Karuga drm_dbg(&i915->drm, "GGTT size = %lluM\n", ggtt->vm.total >> 20); 117036034c95SWambui Karuga drm_dbg(&i915->drm, "GMADR size = %lluM\n", 117136034c95SWambui Karuga (u64)ggtt->mappable_end >> 20); 117236034c95SWambui Karuga drm_dbg(&i915->drm, "DSM size = %lluM\n", 11732c86e55dSMatthew Auld (u64)resource_size(&intel_graphics_stolen_res) >> 20); 11742c86e55dSMatthew Auld 11752c86e55dSMatthew Auld return 0; 11762c86e55dSMatthew Auld } 11772c86e55dSMatthew Auld 11782c86e55dSMatthew Auld /** 11792c86e55dSMatthew Auld * i915_ggtt_probe_hw - Probe GGTT hardware location 11802c86e55dSMatthew Auld * @i915: i915 device 11812c86e55dSMatthew Auld */ 11822c86e55dSMatthew Auld int i915_ggtt_probe_hw(struct drm_i915_private *i915) 11832c86e55dSMatthew Auld { 11842c86e55dSMatthew Auld int ret; 11852c86e55dSMatthew Auld 11862c86e55dSMatthew Auld ret = ggtt_probe_hw(&i915->ggtt, &i915->gt); 11872c86e55dSMatthew Auld if (ret) 11882c86e55dSMatthew Auld return ret; 11892c86e55dSMatthew Auld 11902c86e55dSMatthew Auld if (intel_vtd_active()) 1191dc483ba5SJani Nikula drm_info(&i915->drm, "VT-d active for gfx access\n"); 11922c86e55dSMatthew Auld 11932c86e55dSMatthew Auld return 0; 11942c86e55dSMatthew Auld } 11952c86e55dSMatthew Auld 11962c86e55dSMatthew Auld int i915_ggtt_enable_hw(struct drm_i915_private *i915) 11972c86e55dSMatthew Auld { 11982c86e55dSMatthew Auld if (INTEL_GEN(i915) < 6 && !intel_enable_gtt()) 11992c86e55dSMatthew Auld return -EIO; 12002c86e55dSMatthew Auld 12012c86e55dSMatthew Auld return 0; 12022c86e55dSMatthew Auld } 12032c86e55dSMatthew Auld 12042c86e55dSMatthew Auld void i915_ggtt_enable_guc(struct i915_ggtt *ggtt) 12052c86e55dSMatthew Auld { 12062c86e55dSMatthew Auld GEM_BUG_ON(ggtt->invalidate != gen8_ggtt_invalidate); 12072c86e55dSMatthew Auld 12082c86e55dSMatthew Auld ggtt->invalidate = guc_ggtt_invalidate; 12092c86e55dSMatthew Auld 12102c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12112c86e55dSMatthew Auld } 12122c86e55dSMatthew Auld 12132c86e55dSMatthew Auld void i915_ggtt_disable_guc(struct i915_ggtt *ggtt) 12142c86e55dSMatthew Auld { 12152c86e55dSMatthew Auld /* XXX Temporary pardon for error unload */ 12162c86e55dSMatthew Auld if (ggtt->invalidate == gen8_ggtt_invalidate) 12172c86e55dSMatthew Auld return; 12182c86e55dSMatthew Auld 12192c86e55dSMatthew Auld /* We should only be called after i915_ggtt_enable_guc() */ 12202c86e55dSMatthew Auld GEM_BUG_ON(ggtt->invalidate != guc_ggtt_invalidate); 12212c86e55dSMatthew Auld 12222c86e55dSMatthew Auld ggtt->invalidate = gen8_ggtt_invalidate; 12232c86e55dSMatthew Auld 12242c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12252c86e55dSMatthew Auld } 12262c86e55dSMatthew Auld 1227e986209cSChris Wilson void i915_ggtt_resume(struct i915_ggtt *ggtt) 12282c86e55dSMatthew Auld { 122980e5351dSChris Wilson struct i915_vma *vma; 12302c86e55dSMatthew Auld bool flush = false; 12312c86e55dSMatthew Auld int open; 12322c86e55dSMatthew Auld 12332c86e55dSMatthew Auld intel_gt_check_and_clear_faults(ggtt->vm.gt); 12342c86e55dSMatthew Auld 12352c86e55dSMatthew Auld /* First fill our portion of the GTT with scratch pages */ 12362c86e55dSMatthew Auld ggtt->vm.clear_range(&ggtt->vm, 0, ggtt->vm.total); 12372c86e55dSMatthew Auld 12382c86e55dSMatthew Auld /* Skip rewriting PTE on VMA unbind. */ 12392c86e55dSMatthew Auld open = atomic_xchg(&ggtt->vm.open, 0); 12402c86e55dSMatthew Auld 12412c86e55dSMatthew Auld /* clflush objects bound into the GGTT and rebind them. */ 124280e5351dSChris Wilson list_for_each_entry(vma, &ggtt->vm.bound_list, vm_link) { 12432c86e55dSMatthew Auld struct drm_i915_gem_object *obj = vma->obj; 1244cd0452aaSChris Wilson unsigned int was_bound = 1245cd0452aaSChris Wilson atomic_read(&vma->flags) & I915_VMA_BIND_MASK; 12462c86e55dSMatthew Auld 1247cd0452aaSChris Wilson GEM_BUG_ON(!was_bound); 1248cd0452aaSChris Wilson vma->ops->bind_vma(&ggtt->vm, NULL, vma, 12492c86e55dSMatthew Auld obj ? obj->cache_level : 0, 1250cd0452aaSChris Wilson was_bound); 12512c86e55dSMatthew Auld if (obj) { /* only used during resume => exclusive access */ 12522c86e55dSMatthew Auld flush |= fetch_and_zero(&obj->write_domain); 12532c86e55dSMatthew Auld obj->read_domains |= I915_GEM_DOMAIN_GTT; 12542c86e55dSMatthew Auld } 12552c86e55dSMatthew Auld } 12562c86e55dSMatthew Auld 12572c86e55dSMatthew Auld atomic_set(&ggtt->vm.open, open); 12582c86e55dSMatthew Auld ggtt->invalidate(ggtt); 12592c86e55dSMatthew Auld 12602c86e55dSMatthew Auld if (flush) 12612c86e55dSMatthew Auld wbinvd_on_all_cpus(); 12622c86e55dSMatthew Auld 1263e986209cSChris Wilson if (INTEL_GEN(ggtt->vm.i915) >= 8) 12642c86e55dSMatthew Auld setup_private_pat(ggtt->vm.gt->uncore); 1265dec9cf9eSChris Wilson 1266dec9cf9eSChris Wilson intel_ggtt_restore_fences(ggtt); 12672c86e55dSMatthew Auld } 12682c86e55dSMatthew Auld 12692c86e55dSMatthew Auld static struct scatterlist * 12702c86e55dSMatthew Auld rotate_pages(struct drm_i915_gem_object *obj, unsigned int offset, 12712c86e55dSMatthew Auld unsigned int width, unsigned int height, 1272a4606d45SImre Deak unsigned int src_stride, unsigned int dst_stride, 12732c86e55dSMatthew Auld struct sg_table *st, struct scatterlist *sg) 12742c86e55dSMatthew Auld { 12752c86e55dSMatthew Auld unsigned int column, row; 12762c86e55dSMatthew Auld unsigned int src_idx; 12772c86e55dSMatthew Auld 12782c86e55dSMatthew Auld for (column = 0; column < width; column++) { 1279a4606d45SImre Deak unsigned int left; 1280a4606d45SImre Deak 1281a4606d45SImre Deak src_idx = src_stride * (height - 1) + column + offset; 12822c86e55dSMatthew Auld for (row = 0; row < height; row++) { 12832c86e55dSMatthew Auld st->nents++; 12842c86e55dSMatthew Auld /* 12852c86e55dSMatthew Auld * We don't need the pages, but need to initialize 12862c86e55dSMatthew Auld * the entries so the sg list can be happily traversed. 12872c86e55dSMatthew Auld * The only thing we need are DMA addresses. 12882c86e55dSMatthew Auld */ 12892c86e55dSMatthew Auld sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0); 12902c86e55dSMatthew Auld sg_dma_address(sg) = 12912c86e55dSMatthew Auld i915_gem_object_get_dma_address(obj, src_idx); 12922c86e55dSMatthew Auld sg_dma_len(sg) = I915_GTT_PAGE_SIZE; 12932c86e55dSMatthew Auld sg = sg_next(sg); 1294a4606d45SImre Deak src_idx -= src_stride; 12952c86e55dSMatthew Auld } 1296a4606d45SImre Deak 1297a4606d45SImre Deak left = (dst_stride - height) * I915_GTT_PAGE_SIZE; 1298a4606d45SImre Deak 1299a4606d45SImre Deak if (!left) 1300a4606d45SImre Deak continue; 1301a4606d45SImre Deak 1302a4606d45SImre Deak st->nents++; 1303a4606d45SImre Deak 1304a4606d45SImre Deak /* 1305a4606d45SImre Deak * The DE ignores the PTEs for the padding tiles, the sg entry 1306a4606d45SImre Deak * here is just a conenience to indicate how many padding PTEs 1307a4606d45SImre Deak * to insert at this spot. 1308a4606d45SImre Deak */ 1309a4606d45SImre Deak sg_set_page(sg, NULL, left, 0); 1310a4606d45SImre Deak sg_dma_address(sg) = 0; 1311a4606d45SImre Deak sg_dma_len(sg) = left; 1312a4606d45SImre Deak sg = sg_next(sg); 13132c86e55dSMatthew Auld } 13142c86e55dSMatthew Auld 13152c86e55dSMatthew Auld return sg; 13162c86e55dSMatthew Auld } 13172c86e55dSMatthew Auld 13182c86e55dSMatthew Auld static noinline struct sg_table * 13192c86e55dSMatthew Auld intel_rotate_pages(struct intel_rotation_info *rot_info, 13202c86e55dSMatthew Auld struct drm_i915_gem_object *obj) 13212c86e55dSMatthew Auld { 13222c86e55dSMatthew Auld unsigned int size = intel_rotation_info_size(rot_info); 132352ce7074SWambui Karuga struct drm_i915_private *i915 = to_i915(obj->base.dev); 13242c86e55dSMatthew Auld struct sg_table *st; 13252c86e55dSMatthew Auld struct scatterlist *sg; 13262c86e55dSMatthew Auld int ret = -ENOMEM; 13272c86e55dSMatthew Auld int i; 13282c86e55dSMatthew Auld 13292c86e55dSMatthew Auld /* Allocate target SG list. */ 13302c86e55dSMatthew Auld st = kmalloc(sizeof(*st), GFP_KERNEL); 13312c86e55dSMatthew Auld if (!st) 13322c86e55dSMatthew Auld goto err_st_alloc; 13332c86e55dSMatthew Auld 13342c86e55dSMatthew Auld ret = sg_alloc_table(st, size, GFP_KERNEL); 13352c86e55dSMatthew Auld if (ret) 13362c86e55dSMatthew Auld goto err_sg_alloc; 13372c86e55dSMatthew Auld 13382c86e55dSMatthew Auld st->nents = 0; 13392c86e55dSMatthew Auld sg = st->sgl; 13402c86e55dSMatthew Auld 1341a4606d45SImre Deak for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++) 13422c86e55dSMatthew Auld sg = rotate_pages(obj, rot_info->plane[i].offset, 13432c86e55dSMatthew Auld rot_info->plane[i].width, rot_info->plane[i].height, 1344a4606d45SImre Deak rot_info->plane[i].src_stride, 1345a4606d45SImre Deak rot_info->plane[i].dst_stride, 1346a4606d45SImre Deak st, sg); 13472c86e55dSMatthew Auld 13482c86e55dSMatthew Auld return st; 13492c86e55dSMatthew Auld 13502c86e55dSMatthew Auld err_sg_alloc: 13512c86e55dSMatthew Auld kfree(st); 13522c86e55dSMatthew Auld err_st_alloc: 13532c86e55dSMatthew Auld 135452ce7074SWambui Karuga drm_dbg(&i915->drm, "Failed to create rotated mapping for object size %zu! (%ux%u tiles, %u pages)\n", 135552ce7074SWambui Karuga obj->base.size, rot_info->plane[0].width, 135652ce7074SWambui Karuga rot_info->plane[0].height, size); 13572c86e55dSMatthew Auld 13582c86e55dSMatthew Auld return ERR_PTR(ret); 13592c86e55dSMatthew Auld } 13602c86e55dSMatthew Auld 13612c86e55dSMatthew Auld static struct scatterlist * 13622c86e55dSMatthew Auld remap_pages(struct drm_i915_gem_object *obj, unsigned int offset, 13632c86e55dSMatthew Auld unsigned int width, unsigned int height, 1364a4606d45SImre Deak unsigned int src_stride, unsigned int dst_stride, 13652c86e55dSMatthew Auld struct sg_table *st, struct scatterlist *sg) 13662c86e55dSMatthew Auld { 13672c86e55dSMatthew Auld unsigned int row; 13682c86e55dSMatthew Auld 13692c86e55dSMatthew Auld for (row = 0; row < height; row++) { 13702c86e55dSMatthew Auld unsigned int left = width * I915_GTT_PAGE_SIZE; 13712c86e55dSMatthew Auld 13722c86e55dSMatthew Auld while (left) { 13732c86e55dSMatthew Auld dma_addr_t addr; 13742c86e55dSMatthew Auld unsigned int length; 13752c86e55dSMatthew Auld 13762c86e55dSMatthew Auld /* 13772c86e55dSMatthew Auld * We don't need the pages, but need to initialize 13782c86e55dSMatthew Auld * the entries so the sg list can be happily traversed. 13792c86e55dSMatthew Auld * The only thing we need are DMA addresses. 13802c86e55dSMatthew Auld */ 13812c86e55dSMatthew Auld 13822c86e55dSMatthew Auld addr = i915_gem_object_get_dma_address_len(obj, offset, &length); 13832c86e55dSMatthew Auld 13842c86e55dSMatthew Auld length = min(left, length); 13852c86e55dSMatthew Auld 13862c86e55dSMatthew Auld st->nents++; 13872c86e55dSMatthew Auld 13882c86e55dSMatthew Auld sg_set_page(sg, NULL, length, 0); 13892c86e55dSMatthew Auld sg_dma_address(sg) = addr; 13902c86e55dSMatthew Auld sg_dma_len(sg) = length; 13912c86e55dSMatthew Auld sg = sg_next(sg); 13922c86e55dSMatthew Auld 13932c86e55dSMatthew Auld offset += length / I915_GTT_PAGE_SIZE; 13942c86e55dSMatthew Auld left -= length; 13952c86e55dSMatthew Auld } 13962c86e55dSMatthew Auld 1397a4606d45SImre Deak offset += src_stride - width; 1398a4606d45SImre Deak 1399a4606d45SImre Deak left = (dst_stride - width) * I915_GTT_PAGE_SIZE; 1400a4606d45SImre Deak 1401a4606d45SImre Deak if (!left) 1402a4606d45SImre Deak continue; 1403a4606d45SImre Deak 1404a4606d45SImre Deak st->nents++; 1405a4606d45SImre Deak 1406a4606d45SImre Deak /* 1407a4606d45SImre Deak * The DE ignores the PTEs for the padding tiles, the sg entry 1408a4606d45SImre Deak * here is just a conenience to indicate how many padding PTEs 1409a4606d45SImre Deak * to insert at this spot. 1410a4606d45SImre Deak */ 1411a4606d45SImre Deak sg_set_page(sg, NULL, left, 0); 1412a4606d45SImre Deak sg_dma_address(sg) = 0; 1413a4606d45SImre Deak sg_dma_len(sg) = left; 1414a4606d45SImre Deak sg = sg_next(sg); 14152c86e55dSMatthew Auld } 14162c86e55dSMatthew Auld 14172c86e55dSMatthew Auld return sg; 14182c86e55dSMatthew Auld } 14192c86e55dSMatthew Auld 14202c86e55dSMatthew Auld static noinline struct sg_table * 14212c86e55dSMatthew Auld intel_remap_pages(struct intel_remapped_info *rem_info, 14222c86e55dSMatthew Auld struct drm_i915_gem_object *obj) 14232c86e55dSMatthew Auld { 14242c86e55dSMatthew Auld unsigned int size = intel_remapped_info_size(rem_info); 142552ce7074SWambui Karuga struct drm_i915_private *i915 = to_i915(obj->base.dev); 14262c86e55dSMatthew Auld struct sg_table *st; 14272c86e55dSMatthew Auld struct scatterlist *sg; 14282c86e55dSMatthew Auld int ret = -ENOMEM; 14292c86e55dSMatthew Auld int i; 14302c86e55dSMatthew Auld 14312c86e55dSMatthew Auld /* Allocate target SG list. */ 14322c86e55dSMatthew Auld st = kmalloc(sizeof(*st), GFP_KERNEL); 14332c86e55dSMatthew Auld if (!st) 14342c86e55dSMatthew Auld goto err_st_alloc; 14352c86e55dSMatthew Auld 14362c86e55dSMatthew Auld ret = sg_alloc_table(st, size, GFP_KERNEL); 14372c86e55dSMatthew Auld if (ret) 14382c86e55dSMatthew Auld goto err_sg_alloc; 14392c86e55dSMatthew Auld 14402c86e55dSMatthew Auld st->nents = 0; 14412c86e55dSMatthew Auld sg = st->sgl; 14422c86e55dSMatthew Auld 14432c86e55dSMatthew Auld for (i = 0 ; i < ARRAY_SIZE(rem_info->plane); i++) { 14442c86e55dSMatthew Auld sg = remap_pages(obj, rem_info->plane[i].offset, 14452c86e55dSMatthew Auld rem_info->plane[i].width, rem_info->plane[i].height, 1446a4606d45SImre Deak rem_info->plane[i].src_stride, rem_info->plane[i].dst_stride, 1447a4606d45SImre Deak st, sg); 14482c86e55dSMatthew Auld } 14492c86e55dSMatthew Auld 14502c86e55dSMatthew Auld i915_sg_trim(st); 14512c86e55dSMatthew Auld 14522c86e55dSMatthew Auld return st; 14532c86e55dSMatthew Auld 14542c86e55dSMatthew Auld err_sg_alloc: 14552c86e55dSMatthew Auld kfree(st); 14562c86e55dSMatthew Auld err_st_alloc: 14572c86e55dSMatthew Auld 145852ce7074SWambui Karuga drm_dbg(&i915->drm, "Failed to create remapped mapping for object size %zu! (%ux%u tiles, %u pages)\n", 145952ce7074SWambui Karuga obj->base.size, rem_info->plane[0].width, 146052ce7074SWambui Karuga rem_info->plane[0].height, size); 14612c86e55dSMatthew Auld 14622c86e55dSMatthew Auld return ERR_PTR(ret); 14632c86e55dSMatthew Auld } 14642c86e55dSMatthew Auld 14652c86e55dSMatthew Auld static noinline struct sg_table * 14662c86e55dSMatthew Auld intel_partial_pages(const struct i915_ggtt_view *view, 14672c86e55dSMatthew Auld struct drm_i915_gem_object *obj) 14682c86e55dSMatthew Auld { 14692c86e55dSMatthew Auld struct sg_table *st; 14702c86e55dSMatthew Auld struct scatterlist *sg, *iter; 14712c86e55dSMatthew Auld unsigned int count = view->partial.size; 14722c86e55dSMatthew Auld unsigned int offset; 14732c86e55dSMatthew Auld int ret = -ENOMEM; 14742c86e55dSMatthew Auld 14752c86e55dSMatthew Auld st = kmalloc(sizeof(*st), GFP_KERNEL); 14762c86e55dSMatthew Auld if (!st) 14772c86e55dSMatthew Auld goto err_st_alloc; 14782c86e55dSMatthew Auld 14792c86e55dSMatthew Auld ret = sg_alloc_table(st, count, GFP_KERNEL); 14802c86e55dSMatthew Auld if (ret) 14812c86e55dSMatthew Auld goto err_sg_alloc; 14822c86e55dSMatthew Auld 14830edbb9baSMaarten Lankhorst iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset, true); 14842c86e55dSMatthew Auld GEM_BUG_ON(!iter); 14852c86e55dSMatthew Auld 14862c86e55dSMatthew Auld sg = st->sgl; 14872c86e55dSMatthew Auld st->nents = 0; 14882c86e55dSMatthew Auld do { 14892c86e55dSMatthew Auld unsigned int len; 14902c86e55dSMatthew Auld 1491934941edSTvrtko Ursulin len = min(sg_dma_len(iter) - (offset << PAGE_SHIFT), 14922c86e55dSMatthew Auld count << PAGE_SHIFT); 14932c86e55dSMatthew Auld sg_set_page(sg, NULL, len, 0); 14942c86e55dSMatthew Auld sg_dma_address(sg) = 14952c86e55dSMatthew Auld sg_dma_address(iter) + (offset << PAGE_SHIFT); 14962c86e55dSMatthew Auld sg_dma_len(sg) = len; 14972c86e55dSMatthew Auld 14982c86e55dSMatthew Auld st->nents++; 14992c86e55dSMatthew Auld count -= len >> PAGE_SHIFT; 15002c86e55dSMatthew Auld if (count == 0) { 15012c86e55dSMatthew Auld sg_mark_end(sg); 15022c86e55dSMatthew Auld i915_sg_trim(st); /* Drop any unused tail entries. */ 15032c86e55dSMatthew Auld 15042c86e55dSMatthew Auld return st; 15052c86e55dSMatthew Auld } 15062c86e55dSMatthew Auld 15072c86e55dSMatthew Auld sg = __sg_next(sg); 15082c86e55dSMatthew Auld iter = __sg_next(iter); 15092c86e55dSMatthew Auld offset = 0; 15102c86e55dSMatthew Auld } while (1); 15112c86e55dSMatthew Auld 15122c86e55dSMatthew Auld err_sg_alloc: 15132c86e55dSMatthew Auld kfree(st); 15142c86e55dSMatthew Auld err_st_alloc: 15152c86e55dSMatthew Auld return ERR_PTR(ret); 15162c86e55dSMatthew Auld } 15172c86e55dSMatthew Auld 15182c86e55dSMatthew Auld static int 15192c86e55dSMatthew Auld i915_get_ggtt_vma_pages(struct i915_vma *vma) 15202c86e55dSMatthew Auld { 15212c86e55dSMatthew Auld int ret; 15222c86e55dSMatthew Auld 15232c86e55dSMatthew Auld /* 15242c86e55dSMatthew Auld * The vma->pages are only valid within the lifespan of the borrowed 15252c86e55dSMatthew Auld * obj->mm.pages. When the obj->mm.pages sg_table is regenerated, so 15262c86e55dSMatthew Auld * must be the vma->pages. A simple rule is that vma->pages must only 15272c86e55dSMatthew Auld * be accessed when the obj->mm.pages are pinned. 15282c86e55dSMatthew Auld */ 15292c86e55dSMatthew Auld GEM_BUG_ON(!i915_gem_object_has_pinned_pages(vma->obj)); 15302c86e55dSMatthew Auld 15312c86e55dSMatthew Auld switch (vma->ggtt_view.type) { 15322c86e55dSMatthew Auld default: 15332c86e55dSMatthew Auld GEM_BUG_ON(vma->ggtt_view.type); 1534df561f66SGustavo A. R. Silva fallthrough; 15352c86e55dSMatthew Auld case I915_GGTT_VIEW_NORMAL: 15362c86e55dSMatthew Auld vma->pages = vma->obj->mm.pages; 15372c86e55dSMatthew Auld return 0; 15382c86e55dSMatthew Auld 15392c86e55dSMatthew Auld case I915_GGTT_VIEW_ROTATED: 15402c86e55dSMatthew Auld vma->pages = 15412c86e55dSMatthew Auld intel_rotate_pages(&vma->ggtt_view.rotated, vma->obj); 15422c86e55dSMatthew Auld break; 15432c86e55dSMatthew Auld 15442c86e55dSMatthew Auld case I915_GGTT_VIEW_REMAPPED: 15452c86e55dSMatthew Auld vma->pages = 15462c86e55dSMatthew Auld intel_remap_pages(&vma->ggtt_view.remapped, vma->obj); 15472c86e55dSMatthew Auld break; 15482c86e55dSMatthew Auld 15492c86e55dSMatthew Auld case I915_GGTT_VIEW_PARTIAL: 15502c86e55dSMatthew Auld vma->pages = intel_partial_pages(&vma->ggtt_view, vma->obj); 15512c86e55dSMatthew Auld break; 15522c86e55dSMatthew Auld } 15532c86e55dSMatthew Auld 15542c86e55dSMatthew Auld ret = 0; 15552c86e55dSMatthew Auld if (IS_ERR(vma->pages)) { 15562c86e55dSMatthew Auld ret = PTR_ERR(vma->pages); 15572c86e55dSMatthew Auld vma->pages = NULL; 155852ce7074SWambui Karuga drm_err(&vma->vm->i915->drm, 155952ce7074SWambui Karuga "Failed to get pages for VMA view type %u (%d)!\n", 15602c86e55dSMatthew Auld vma->ggtt_view.type, ret); 15612c86e55dSMatthew Auld } 15622c86e55dSMatthew Auld return ret; 15632c86e55dSMatthew Auld } 1564