drm/i915: Preallocate stashes for vma page-directories
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / gt / intel_ppgtt.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2020 Intel Corporation
4  */
5
6 #include <linux/slab.h>
7
8 #include "i915_trace.h"
9 #include "intel_gtt.h"
10 #include "gen6_ppgtt.h"
11 #include "gen8_ppgtt.h"
12
13 struct i915_page_table *alloc_pt(struct i915_address_space *vm)
14 {
15         struct i915_page_table *pt;
16
17         pt = kmalloc(sizeof(*pt), I915_GFP_ALLOW_FAIL);
18         if (unlikely(!pt))
19                 return ERR_PTR(-ENOMEM);
20
21         if (unlikely(setup_page_dma(vm, &pt->base))) {
22                 kfree(pt);
23                 return ERR_PTR(-ENOMEM);
24         }
25
26         atomic_set(&pt->used, 0);
27         return pt;
28 }
29
30 struct i915_page_directory *__alloc_pd(size_t sz)
31 {
32         struct i915_page_directory *pd;
33
34         pd = kzalloc(sz, I915_GFP_ALLOW_FAIL);
35         if (unlikely(!pd))
36                 return NULL;
37
38         spin_lock_init(&pd->lock);
39         return pd;
40 }
41
42 struct i915_page_directory *alloc_pd(struct i915_address_space *vm)
43 {
44         struct i915_page_directory *pd;
45
46         pd = __alloc_pd(sizeof(*pd));
47         if (unlikely(!pd))
48                 return ERR_PTR(-ENOMEM);
49
50         if (unlikely(setup_page_dma(vm, px_base(pd)))) {
51                 kfree(pd);
52                 return ERR_PTR(-ENOMEM);
53         }
54
55         return pd;
56 }
57
58 void free_pd(struct i915_address_space *vm, struct i915_page_dma *pd)
59 {
60         cleanup_page_dma(vm, pd);
61         kfree(pd);
62 }
63
64 static inline void
65 write_dma_entry(struct i915_page_dma * const pdma,
66                 const unsigned short idx,
67                 const u64 encoded_entry)
68 {
69         u64 * const vaddr = kmap_atomic(pdma->page);
70
71         vaddr[idx] = encoded_entry;
72         kunmap_atomic(vaddr);
73 }
74
75 void
76 __set_pd_entry(struct i915_page_directory * const pd,
77                const unsigned short idx,
78                struct i915_page_dma * const to,
79                u64 (*encode)(const dma_addr_t, const enum i915_cache_level))
80 {
81         /* Each thread pre-pins the pd, and we may have a thread per pde. */
82         GEM_BUG_ON(atomic_read(px_used(pd)) > NALLOC * ARRAY_SIZE(pd->entry));
83
84         atomic_inc(px_used(pd));
85         pd->entry[idx] = to;
86         write_dma_entry(px_base(pd), idx, encode(to->daddr, I915_CACHE_LLC));
87 }
88
89 void
90 clear_pd_entry(struct i915_page_directory * const pd,
91                const unsigned short idx,
92                const struct i915_page_scratch * const scratch)
93 {
94         GEM_BUG_ON(atomic_read(px_used(pd)) == 0);
95
96         write_dma_entry(px_base(pd), idx, scratch->encode);
97         pd->entry[idx] = NULL;
98         atomic_dec(px_used(pd));
99 }
100
101 bool
102 release_pd_entry(struct i915_page_directory * const pd,
103                  const unsigned short idx,
104                  struct i915_page_table * const pt,
105                  const struct i915_page_scratch * const scratch)
106 {
107         bool free = false;
108
109         if (atomic_add_unless(&pt->used, -1, 1))
110                 return false;
111
112         spin_lock(&pd->lock);
113         if (atomic_dec_and_test(&pt->used)) {
114                 clear_pd_entry(pd, idx, scratch);
115                 free = true;
116         }
117         spin_unlock(&pd->lock);
118
119         return free;
120 }
121
122 int i915_ppgtt_init_hw(struct intel_gt *gt)
123 {
124         struct drm_i915_private *i915 = gt->i915;
125
126         gtt_write_workarounds(gt);
127
128         if (IS_GEN(i915, 6))
129                 gen6_ppgtt_enable(gt);
130         else if (IS_GEN(i915, 7))
131                 gen7_ppgtt_enable(gt);
132
133         return 0;
134 }
135
136 static struct i915_ppgtt *
137 __ppgtt_create(struct intel_gt *gt)
138 {
139         if (INTEL_GEN(gt->i915) < 8)
140                 return gen6_ppgtt_create(gt);
141         else
142                 return gen8_ppgtt_create(gt);
143 }
144
145 struct i915_ppgtt *i915_ppgtt_create(struct intel_gt *gt)
146 {
147         struct i915_ppgtt *ppgtt;
148
149         ppgtt = __ppgtt_create(gt);
150         if (IS_ERR(ppgtt))
151                 return ppgtt;
152
153         trace_i915_ppgtt_create(&ppgtt->vm);
154
155         return ppgtt;
156 }
157
158 void ppgtt_bind_vma(struct i915_address_space *vm,
159                     struct i915_vm_pt_stash *stash,
160                     struct i915_vma *vma,
161                     enum i915_cache_level cache_level,
162                     u32 flags)
163 {
164         u32 pte_flags;
165
166         if (!test_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma))) {
167                 vm->allocate_va_range(vm, stash, vma->node.start, vma->size);
168                 set_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma));
169         }
170
171         /* Applicable to VLV, and gen8+ */
172         pte_flags = 0;
173         if (i915_gem_object_is_readonly(vma->obj))
174                 pte_flags |= PTE_READ_ONLY;
175
176         vm->insert_entries(vm, vma, cache_level, pte_flags);
177         wmb();
178 }
179
180 void ppgtt_unbind_vma(struct i915_address_space *vm, struct i915_vma *vma)
181 {
182         if (test_and_clear_bit(I915_VMA_ALLOC_BIT, __i915_vma_flags(vma)))
183                 vm->clear_range(vm, vma->node.start, vma->size);
184 }
185
186 static unsigned long pd_count(u64 size, int shift)
187 {
188         /* Beware later misalignment */
189         return (size + 2 * (BIT_ULL(shift) - 1)) >> shift;
190 }
191
192 int i915_vm_alloc_pt_stash(struct i915_address_space *vm,
193                            struct i915_vm_pt_stash *stash,
194                            u64 size)
195 {
196         unsigned long count;
197         int shift, n;
198
199         shift = vm->pd_shift;
200         if (!shift)
201                 return 0;
202
203         count = pd_count(size, shift);
204         while (count--) {
205                 struct i915_page_table *pt;
206
207                 pt = alloc_pt(vm);
208                 if (IS_ERR(pt)) {
209                         i915_vm_free_pt_stash(vm, stash);
210                         return PTR_ERR(pt);
211                 }
212
213                 pt->stash = stash->pt[0];
214                 stash->pt[0] = pt;
215         }
216
217         for (n = 1; n < vm->top; n++) {
218                 shift += ilog2(I915_PDES); /* Each PD holds 512 entries */
219                 count = pd_count(size, shift);
220                 while (count--) {
221                         struct i915_page_directory *pd;
222
223                         pd = alloc_pd(vm);
224                         if (IS_ERR(pd)) {
225                                 i915_vm_free_pt_stash(vm, stash);
226                                 return PTR_ERR(pd);
227                         }
228
229                         pd->pt.stash = stash->pt[1];
230                         stash->pt[1] = &pd->pt;
231                 }
232         }
233
234         return 0;
235 }
236
237 void i915_vm_free_pt_stash(struct i915_address_space *vm,
238                            struct i915_vm_pt_stash *stash)
239 {
240         struct i915_page_table *pt;
241         int n;
242
243         for (n = 0; n < ARRAY_SIZE(stash->pt); n++) {
244                 while ((pt = stash->pt[n])) {
245                         stash->pt[n] = pt->stash;
246                         free_px(vm, pt);
247                 }
248         }
249 }
250
251 int ppgtt_set_pages(struct i915_vma *vma)
252 {
253         GEM_BUG_ON(vma->pages);
254
255         vma->pages = vma->obj->mm.pages;
256         vma->page_sizes = vma->obj->mm.page_sizes;
257
258         return 0;
259 }
260
261 void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt)
262 {
263         struct drm_i915_private *i915 = gt->i915;
264
265         ppgtt->vm.gt = gt;
266         ppgtt->vm.i915 = i915;
267         ppgtt->vm.dma = &i915->drm.pdev->dev;
268         ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size);
269
270         i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
271
272         ppgtt->vm.vma_ops.bind_vma    = ppgtt_bind_vma;
273         ppgtt->vm.vma_ops.unbind_vma  = ppgtt_unbind_vma;
274         ppgtt->vm.vma_ops.set_pages   = ppgtt_set_pages;
275         ppgtt->vm.vma_ops.clear_pages = clear_pages;
276 }