1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <drm/drmP.h>
25#include "amdgpu.h"
26#include "amdgpu_ih.h"
27#include "amdgpu_amdkfd.h"
28
29
30
31
32
33
34
35
36
37static int amdgpu_ih_ring_alloc(struct amdgpu_device *adev)
38{
39 int r;
40
41
42 if (adev->irq.ih.ring_obj == NULL) {
43 r = amdgpu_bo_create_kernel(adev, adev->irq.ih.ring_size,
44 PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
45 &adev->irq.ih.ring_obj,
46 &adev->irq.ih.gpu_addr,
47 (void **)&adev->irq.ih.ring);
48 if (r) {
49 DRM_ERROR("amdgpu: failed to create ih ring buffer (%d).\n", r);
50 return r;
51 }
52 }
53 return 0;
54}
55
56
57
58
59
60
61
62
63
64
65int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size,
66 bool use_bus_addr)
67{
68 u32 rb_bufsz;
69 int r;
70
71
72 rb_bufsz = order_base_2(ring_size / 4);
73 ring_size = (1 << rb_bufsz) * 4;
74 adev->irq.ih.ring_size = ring_size;
75 adev->irq.ih.ptr_mask = adev->irq.ih.ring_size - 1;
76 adev->irq.ih.rptr = 0;
77 adev->irq.ih.use_bus_addr = use_bus_addr;
78
79 if (adev->irq.ih.use_bus_addr) {
80 if (!adev->irq.ih.ring) {
81
82
83
84 adev->irq.ih.ring = pci_alloc_consistent(adev->pdev,
85 adev->irq.ih.ring_size + 8,
86 &adev->irq.ih.rb_dma_addr);
87 if (adev->irq.ih.ring == NULL)
88 return -ENOMEM;
89 memset((void *)adev->irq.ih.ring, 0, adev->irq.ih.ring_size + 8);
90 adev->irq.ih.wptr_offs = (adev->irq.ih.ring_size / 4) + 0;
91 adev->irq.ih.rptr_offs = (adev->irq.ih.ring_size / 4) + 1;
92 }
93 return 0;
94 } else {
95 r = amdgpu_device_wb_get(adev, &adev->irq.ih.wptr_offs);
96 if (r) {
97 dev_err(adev->dev, "(%d) ih wptr_offs wb alloc failed\n", r);
98 return r;
99 }
100
101 r = amdgpu_device_wb_get(adev, &adev->irq.ih.rptr_offs);
102 if (r) {
103 amdgpu_device_wb_free(adev, adev->irq.ih.wptr_offs);
104 dev_err(adev->dev, "(%d) ih rptr_offs wb alloc failed\n", r);
105 return r;
106 }
107
108 return amdgpu_ih_ring_alloc(adev);
109 }
110}
111
112
113
114
115
116
117
118
119
120void amdgpu_ih_ring_fini(struct amdgpu_device *adev)
121{
122 if (adev->irq.ih.use_bus_addr) {
123 if (adev->irq.ih.ring) {
124
125
126
127 pci_free_consistent(adev->pdev, adev->irq.ih.ring_size + 8,
128 (void *)adev->irq.ih.ring,
129 adev->irq.ih.rb_dma_addr);
130 adev->irq.ih.ring = NULL;
131 }
132 } else {
133 amdgpu_bo_free_kernel(&adev->irq.ih.ring_obj,
134 &adev->irq.ih.gpu_addr,
135 (void **)&adev->irq.ih.ring);
136 amdgpu_device_wb_free(adev, adev->irq.ih.wptr_offs);
137 amdgpu_device_wb_free(adev, adev->irq.ih.rptr_offs);
138 }
139}
140
141
142
143
144
145
146
147
148
149int amdgpu_ih_process(struct amdgpu_device *adev)
150{
151 struct amdgpu_iv_entry entry;
152 u32 wptr;
153
154 if (!adev->irq.ih.enabled || adev->shutdown)
155 return IRQ_NONE;
156
157 wptr = amdgpu_ih_get_wptr(adev);
158
159restart_ih:
160
161 if (atomic_xchg(&adev->irq.ih.lock, 1))
162 return IRQ_NONE;
163
164 DRM_DEBUG("%s: rptr %d, wptr %d\n", __func__, adev->irq.ih.rptr, wptr);
165
166
167 rmb();
168
169 while (adev->irq.ih.rptr != wptr) {
170 u32 ring_index = adev->irq.ih.rptr >> 2;
171
172
173 if (!amdgpu_ih_prescreen_iv(adev)) {
174 adev->irq.ih.rptr &= adev->irq.ih.ptr_mask;
175 continue;
176 }
177
178
179 amdgpu_amdkfd_interrupt(adev,
180 (const void *) &adev->irq.ih.ring[ring_index]);
181
182 entry.iv_entry = (const uint32_t *)
183 &adev->irq.ih.ring[ring_index];
184 amdgpu_ih_decode_iv(adev, &entry);
185 adev->irq.ih.rptr &= adev->irq.ih.ptr_mask;
186
187 amdgpu_irq_dispatch(adev, &entry);
188 }
189 amdgpu_ih_set_rptr(adev);
190 atomic_set(&adev->irq.ih.lock, 0);
191
192
193 wptr = amdgpu_ih_get_wptr(adev);
194 if (wptr != adev->irq.ih.rptr)
195 goto restart_ih;
196
197 return IRQ_HANDLED;
198}
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218int amdgpu_ih_add_fault(struct amdgpu_device *adev, u64 key)
219{
220 unsigned long flags;
221 int r = -ENOSPC;
222
223 if (WARN_ON_ONCE(!adev->irq.ih.faults))
224
225
226
227 return r;
228
229 spin_lock_irqsave(&adev->irq.ih.faults->lock, flags);
230
231
232 if (adev->irq.ih.faults->count >= (1 << (AMDGPU_PAGEFAULT_HASH_BITS-1)))
233 goto unlock_out;
234
235 r = chash_table_copy_in(&adev->irq.ih.faults->hash, key, NULL);
236 if (!r)
237 adev->irq.ih.faults->count++;
238
239
240 WARN_ON_ONCE(r < 0);
241
242unlock_out:
243 spin_unlock_irqrestore(&adev->irq.ih.faults->lock, flags);
244 return r;
245}
246
247
248
249
250
251
252
253
254
255
256
257void amdgpu_ih_clear_fault(struct amdgpu_device *adev, u64 key)
258{
259 unsigned long flags;
260 int r;
261
262 if (!adev->irq.ih.faults)
263 return;
264
265 spin_lock_irqsave(&adev->irq.ih.faults->lock, flags);
266
267 r = chash_table_remove(&adev->irq.ih.faults->hash, key, NULL);
268 if (!WARN_ON_ONCE(r < 0)) {
269 adev->irq.ih.faults->count--;
270 WARN_ON_ONCE(adev->irq.ih.faults->count < 0);
271 }
272
273 spin_unlock_irqrestore(&adev->irq.ih.faults->lock, flags);
274}
275