xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/i915/gt/intel_ppgtt.c (revision a339bc10a1db4ae391ba932d007650565222b735)
1 /*	$NetBSD: intel_ppgtt.c,v 1.4 2021/12/19 12:07:47 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.4 2021/12/19 12:07:47 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 
alloc_pt(struct i915_address_space * vm)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 
__alloc_pd(size_t sz)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 
alloc_pd(struct i915_address_space * vm)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 		spin_lock_destroy(&pd->lock);
57 		kfree(pd);
58 		return ERR_PTR(-ENOMEM);
59 	}
60 
61 	return pd;
62 }
63 
free_pd(struct i915_address_space * vm,struct i915_page_dma * pd)64 void free_pd(struct i915_address_space *vm, struct i915_page_dma *pd)
65 {
66 	cleanup_page_dma(vm, pd);
67 	kfree(pd);
68 }
69 
70 static inline void
write_dma_entry(struct i915_page_dma * const pdma,const unsigned short idx,const u64 encoded_entry)71 write_dma_entry(struct i915_page_dma * const pdma,
72 		const unsigned short idx,
73 		const u64 encoded_entry)
74 {
75 	u64 * const vaddr = kmap_atomic(pdma->page);
76 
77 	vaddr[idx] = encoded_entry;
78 	kunmap_atomic(vaddr);
79 }
80 
81 void
__set_pd_entry(struct i915_page_directory * const pd,const unsigned short idx,struct i915_page_dma * const to,u64 (* encode)(const dma_addr_t,const enum i915_cache_level))82 __set_pd_entry(struct i915_page_directory * const pd,
83 	       const unsigned short idx,
84 	       struct i915_page_dma * const to,
85 	       u64 (*encode)(const dma_addr_t, const enum i915_cache_level))
86 {
87 	/* Each thread pre-pins the pd, and we may have a thread per pde. */
88 	GEM_BUG_ON(atomic_read(px_used(pd)) > NALLOC * ARRAY_SIZE(pd->entry));
89 
90 	atomic_inc(px_used(pd));
91 	pd->entry[idx] = to;
92 #ifdef __NetBSD__
93 	write_dma_entry(px_base(pd), idx, encode(to->map->dm_segs[0].ds_addr, I915_CACHE_LLC));
94 #else
95 	write_dma_entry(px_base(pd), idx, encode(to->daddr, I915_CACHE_LLC));
96 #endif
97 }
98 
99 void
clear_pd_entry(struct i915_page_directory * const pd,const unsigned short idx,const struct i915_page_scratch * const scratch)100 clear_pd_entry(struct i915_page_directory * const pd,
101 	       const unsigned short idx,
102 	       const struct i915_page_scratch * const scratch)
103 {
104 	GEM_BUG_ON(atomic_read(px_used(pd)) == 0);
105 
106 	write_dma_entry(px_base(pd), idx, scratch->encode);
107 	pd->entry[idx] = NULL;
108 	atomic_dec(px_used(pd));
109 }
110 
111 bool
release_pd_entry(struct i915_page_directory * const pd,const unsigned short idx,struct i915_page_table * const pt,const struct i915_page_scratch * const scratch)112 release_pd_entry(struct i915_page_directory * const pd,
113 		 const unsigned short idx,
114 		 struct i915_page_table * const pt,
115 		 const struct i915_page_scratch * const scratch)
116 {
117 	bool free = false;
118 
119 	if (atomic_add_unless(&pt->used, -1, 1))
120 		return false;
121 
122 	spin_lock(&pd->lock);
123 	if (atomic_dec_and_test(&pt->used)) {
124 		clear_pd_entry(pd, idx, scratch);
125 		free = true;
126 	}
127 	spin_unlock(&pd->lock);
128 
129 	return free;
130 }
131 
i915_ppgtt_init_hw(struct intel_gt * gt)132 int i915_ppgtt_init_hw(struct intel_gt *gt)
133 {
134 	struct drm_i915_private *i915 = gt->i915;
135 
136 	gtt_write_workarounds(gt);
137 
138 	if (IS_GEN(i915, 6))
139 		gen6_ppgtt_enable(gt);
140 	else if (IS_GEN(i915, 7))
141 		gen7_ppgtt_enable(gt);
142 
143 	return 0;
144 }
145 
146 static struct i915_ppgtt *
__ppgtt_create(struct intel_gt * gt)147 __ppgtt_create(struct intel_gt *gt)
148 {
149 	if (INTEL_GEN(gt->i915) < 8)
150 		return gen6_ppgtt_create(gt);
151 	else
152 		return gen8_ppgtt_create(gt);
153 }
154 
i915_ppgtt_create(struct intel_gt * gt)155 struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt)
156 {
157 	struct i915_ppgtt *ppgtt;
158 
159 	ppgtt = __ppgtt_create(gt);
160 	if (IS_ERR(ppgtt))
161 		return ppgtt;
162 
163 	trace_i915_ppgtt_create(&ppgtt->vm);
164 
165 	return ppgtt;
166 }
167 
ppgtt_bind_vma(struct i915_vma * vma,enum i915_cache_level cache_level,u32 flags)168 static int ppgtt_bind_vma(struct i915_vma *vma,
169 			  enum i915_cache_level cache_level,
170 			  u32 flags)
171 {
172 	u32 pte_flags;
173 	int err;
174 
175 	if (flags & I915_VMA_ALLOC) {
176 		err = vma->vm->allocate_va_range(vma->vm,
177 						 vma->node.start, vma->size);
178 		if (err)
179 			return err;
180 
181 		set_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma));
182 	}
183 
184 	/* Applicable to VLV, and gen8+ */
185 	pte_flags = 0;
186 	if (i915_gem_object_is_readonly(vma->obj))
187 		pte_flags |= PTE_READ_ONLY;
188 
189 	GEM_BUG_ON(!test_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)));
190 	vma->vm->insert_entries(vma->vm, vma, cache_level, pte_flags);
191 	wmb();
192 
193 	return 0;
194 }
195 
ppgtt_unbind_vma(struct i915_vma * vma)196 static void ppgtt_unbind_vma(struct i915_vma *vma)
197 {
198 	if (test_and_clear_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)))
199 		vma->vm->clear_range(vma->vm, vma->node.start, vma->size);
200 }
201 
ppgtt_set_pages(struct i915_vma * vma)202 int ppgtt_set_pages(struct i915_vma *vma)
203 {
204 	GEM_BUG_ON(vma->pages);
205 
206 	vma->pages = vma->obj->mm.pages;
207 
208 	vma->page_sizes = vma->obj->mm.page_sizes;
209 
210 	return 0;
211 }
212 
ppgtt_init(struct i915_ppgtt * ppgtt,struct intel_gt * gt)213 void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt)
214 {
215 	struct drm_i915_private *i915 = gt->i915;
216 
217 	ppgtt->vm.gt = gt;
218 	ppgtt->vm.i915 = i915;
219 #ifdef __NetBSD__
220 	ppgtt->vm.dmat = i915->drm.dmat;
221 #else
222 	ppgtt->vm.dma = &i915->drm.pdev->dev;
223 #endif
224 	ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size);
225 
226 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
227 
228 	ppgtt->vm.vma_ops.bind_vma    = ppgtt_bind_vma;
229 	ppgtt->vm.vma_ops.unbind_vma  = ppgtt_unbind_vma;
230 	ppgtt->vm.vma_ops.set_pages   = ppgtt_set_pages;
231 	ppgtt->vm.vma_ops.clear_pages = clear_pages;
232 }
233