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