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