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