Home | History | Annotate | Line # | Download | only in gt
intel_ppgtt.c revision 1.1.1.1
      1 /*	$NetBSD: intel_ppgtt.c,v 1.1.1.1 2021/12/18 20:15:32 riastradh Exp $	*/
      2 
      3 // SPDX-License-Identifier: MIT
      4 /*
      5  * Copyright  2020 Intel Corporation
      6  */
      7 
      8 #include <sys/cdefs.h>
      9 __KERNEL_RCSID(0, "$NetBSD: intel_ppgtt.c,v 1.1.1.1 2021/12/18 20:15:32 riastradh Exp $");
     10 
     11 #include <linux/slab.h>
     12 
     13 #include "i915_trace.h"
     14 #include "intel_gtt.h"
     15 #include "gen6_ppgtt.h"
     16 #include "gen8_ppgtt.h"
     17 
     18 struct i915_page_table *alloc_pt(struct i915_address_space *vm)
     19 {
     20 	struct i915_page_table *pt;
     21 
     22 	pt = kmalloc(sizeof(*pt), I915_GFP_ALLOW_FAIL);
     23 	if (unlikely(!pt))
     24 		return ERR_PTR(-ENOMEM);
     25 
     26 	if (unlikely(setup_page_dma(vm, &pt->base))) {
     27 		kfree(pt);
     28 		return ERR_PTR(-ENOMEM);
     29 	}
     30 
     31 	atomic_set(&pt->used, 0);
     32 	return pt;
     33 }
     34 
     35 struct i915_page_directory *__alloc_pd(size_t sz)
     36 {
     37 	struct i915_page_directory *pd;
     38 
     39 	pd = kzalloc(sz, I915_GFP_ALLOW_FAIL);
     40 	if (unlikely(!pd))
     41 		return NULL;
     42 
     43 	spin_lock_init(&pd->lock);
     44 	return pd;
     45 }
     46 
     47 struct i915_page_directory *alloc_pd(struct i915_address_space *vm)
     48 {
     49 	struct i915_page_directory *pd;
     50 
     51 	pd = __alloc_pd(sizeof(*pd));
     52 	if (unlikely(!pd))
     53 		return ERR_PTR(-ENOMEM);
     54 
     55 	if (unlikely(setup_page_dma(vm, px_base(pd)))) {
     56 		kfree(pd);
     57 		return ERR_PTR(-ENOMEM);
     58 	}
     59 
     60 	return pd;
     61 }
     62 
     63 void free_pd(struct i915_address_space *vm, struct i915_page_dma *pd)
     64 {
     65 	cleanup_page_dma(vm, pd);
     66 	kfree(pd);
     67 }
     68 
     69 static inline void
     70 write_dma_entry(struct i915_page_dma * const pdma,
     71 		const unsigned short idx,
     72 		const u64 encoded_entry)
     73 {
     74 	u64 * const vaddr = kmap_atomic(pdma->page);
     75 
     76 	vaddr[idx] = encoded_entry;
     77 	kunmap_atomic(vaddr);
     78 }
     79 
     80 void
     81 __set_pd_entry(struct i915_page_directory * const pd,
     82 	       const unsigned short idx,
     83 	       struct i915_page_dma * const to,
     84 	       u64 (*encode)(const dma_addr_t, const enum i915_cache_level))
     85 {
     86 	/* Each thread pre-pins the pd, and we may have a thread per pde. */
     87 	GEM_BUG_ON(atomic_read(px_used(pd)) > NALLOC * ARRAY_SIZE(pd->entry));
     88 
     89 	atomic_inc(px_used(pd));
     90 	pd->entry[idx] = to;
     91 	write_dma_entry(px_base(pd), idx, encode(to->daddr, I915_CACHE_LLC));
     92 }
     93 
     94 void
     95 clear_pd_entry(struct i915_page_directory * const pd,
     96 	       const unsigned short idx,
     97 	       const struct i915_page_scratch * const scratch)
     98 {
     99 	GEM_BUG_ON(atomic_read(px_used(pd)) == 0);
    100 
    101 	write_dma_entry(px_base(pd), idx, scratch->encode);
    102 	pd->entry[idx] = NULL;
    103 	atomic_dec(px_used(pd));
    104 }
    105 
    106 bool
    107 release_pd_entry(struct i915_page_directory * const pd,
    108 		 const unsigned short idx,
    109 		 struct i915_page_table * const pt,
    110 		 const struct i915_page_scratch * const scratch)
    111 {
    112 	bool free = false;
    113 
    114 	if (atomic_add_unless(&pt->used, -1, 1))
    115 		return false;
    116 
    117 	spin_lock(&pd->lock);
    118 	if (atomic_dec_and_test(&pt->used)) {
    119 		clear_pd_entry(pd, idx, scratch);
    120 		free = true;
    121 	}
    122 	spin_unlock(&pd->lock);
    123 
    124 	return free;
    125 }
    126 
    127 int i915_ppgtt_init_hw(struct intel_gt *gt)
    128 {
    129 	struct drm_i915_private *i915 = gt->i915;
    130 
    131 	gtt_write_workarounds(gt);
    132 
    133 	if (IS_GEN(i915, 6))
    134 		gen6_ppgtt_enable(gt);
    135 	else if (IS_GEN(i915, 7))
    136 		gen7_ppgtt_enable(gt);
    137 
    138 	return 0;
    139 }
    140 
    141 static struct i915_ppgtt *
    142 __ppgtt_create(struct intel_gt *gt)
    143 {
    144 	if (INTEL_GEN(gt->i915) < 8)
    145 		return gen6_ppgtt_create(gt);
    146 	else
    147 		return gen8_ppgtt_create(gt);
    148 }
    149 
    150 struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt)
    151 {
    152 	struct i915_ppgtt *ppgtt;
    153 
    154 	ppgtt = __ppgtt_create(gt);
    155 	if (IS_ERR(ppgtt))
    156 		return ppgtt;
    157 
    158 	trace_i915_ppgtt_create(&ppgtt->vm);
    159 
    160 	return ppgtt;
    161 }
    162 
    163 static int ppgtt_bind_vma(struct i915_vma *vma,
    164 			  enum i915_cache_level cache_level,
    165 			  u32 flags)
    166 {
    167 	u32 pte_flags;
    168 	int err;
    169 
    170 	if (flags & I915_VMA_ALLOC) {
    171 		err = vma->vm->allocate_va_range(vma->vm,
    172 						 vma->node.start, vma->size);
    173 		if (err)
    174 			return err;
    175 
    176 		set_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma));
    177 	}
    178 
    179 	/* Applicable to VLV, and gen8+ */
    180 	pte_flags = 0;
    181 	if (i915_gem_object_is_readonly(vma->obj))
    182 		pte_flags |= PTE_READ_ONLY;
    183 
    184 	GEM_BUG_ON(!test_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)));
    185 	vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
    186 	wmb();
    187 
    188 	return 0;
    189 }
    190 
    191 static void ppgtt_unbind_vma(struct i915_vma *vma)
    192 {
    193 	if (test_and_clear_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)))
    194 		vma->vm->clear_range(vma->vm, vma->node.start, vma->size);
    195 }
    196 
    197 int ppgtt_set_pages(struct i915_vma *vma)
    198 {
    199 	GEM_BUG_ON(vma->pages);
    200 
    201 	vma->pages = vma->obj->mm.pages;
    202 
    203 	vma->page_sizes = vma->obj->mm.page_sizes;
    204 
    205 	return 0;
    206 }
    207 
    208 void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt)
    209 {
    210 	struct drm_i915_private *i915 = gt->i915;
    211 
    212 	ppgtt->vm.gt = gt;
    213 	ppgtt->vm.i915 = i915;
    214 	ppgtt->vm.dma = &i915->drm.pdev->dev;
    215 	ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size);
    216 
    217 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
    218 
    219 	ppgtt->vm.vma_ops.bind_vma    = ppgtt_bind_vma;
    220 	ppgtt->vm.vma_ops.unbind_vma  = ppgtt_unbind_vma;
    221 	ppgtt->vm.vma_ops.set_pages   = ppgtt_set_pages;
    222 	ppgtt->vm.vma_ops.clear_pages = clear_pages;
    223 }
    224