diff options
author | Ken Wang <Qingqing.Wang@amd.com> | 2016-01-19 01:05:23 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2016-08-31 12:10:51 -0400 |
commit | 30d1574fa4c71cf390ae4af57585a850612db8f7 (patch) | |
tree | 05008def85a531fd42f75723e0eaac0c4cd4b5fb /drivers/gpu/drm/amd/amdgpu | |
parent | 2cd46ad22383ab8372b86cdb5257589496099412 (diff) |
drm/amdgpu: add DMA implementation for si v8
v4: rebase fixes
v5: use the generic nop fill
v6: rebase fixes
v7: rebase fixes
copy count fixes from Jonathan
general cleanup
add fill buffer implementation
v8: adapt write_pte and copy_pte to latest changes
Signed-off-by: Ken Wang <Qingqing.Wang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/si_dma.c | 917 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/si_dma.h | 29 |
3 files changed, 950 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index e31ffe819ec7..1d29e128157a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h | |||
@@ -1706,6 +1706,10 @@ struct amdgpu_sdma_instance { | |||
1706 | 1706 | ||
1707 | struct amdgpu_sdma { | 1707 | struct amdgpu_sdma { |
1708 | struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES]; | 1708 | struct amdgpu_sdma_instance instance[AMDGPU_MAX_SDMA_INSTANCES]; |
1709 | #ifdef CONFIG_DRM_AMDGPU_SI | ||
1710 | //SI DMA has a difference trap irq number for the second engine | ||
1711 | struct amdgpu_irq_src trap_irq_1; | ||
1712 | #endif | ||
1709 | struct amdgpu_irq_src trap_irq; | 1713 | struct amdgpu_irq_src trap_irq; |
1710 | struct amdgpu_irq_src illegal_inst_irq; | 1714 | struct amdgpu_irq_src illegal_inst_irq; |
1711 | int num_instances; | 1715 | int num_instances; |
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c new file mode 100644 index 000000000000..377f4ae9e777 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c | |||
@@ -0,0 +1,917 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Alex Deucher | ||
23 | */ | ||
24 | #include <drm/drmP.h> | ||
25 | #include "amdgpu.h" | ||
26 | #include "amdgpu_trace.h" | ||
27 | #include "si/sid.h" | ||
28 | |||
29 | const u32 sdma_offsets[SDMA_MAX_INSTANCE] = | ||
30 | { | ||
31 | DMA0_REGISTER_OFFSET, | ||
32 | DMA1_REGISTER_OFFSET | ||
33 | }; | ||
34 | |||
35 | static void si_dma_set_ring_funcs(struct amdgpu_device *adev); | ||
36 | static void si_dma_set_buffer_funcs(struct amdgpu_device *adev); | ||
37 | static void si_dma_set_vm_pte_funcs(struct amdgpu_device *adev); | ||
38 | static void si_dma_set_irq_funcs(struct amdgpu_device *adev); | ||
39 | |||
40 | static uint32_t si_dma_ring_get_rptr(struct amdgpu_ring *ring) | ||
41 | { | ||
42 | u32 rptr; | ||
43 | |||
44 | rptr = ring->adev->wb.wb[ring->rptr_offs/4]; | ||
45 | |||
46 | return rptr; | ||
47 | } | ||
48 | |||
49 | static uint32_t si_dma_ring_get_wptr(struct amdgpu_ring *ring) | ||
50 | { | ||
51 | |||
52 | struct amdgpu_device *adev = ring->adev; | ||
53 | u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; | ||
54 | |||
55 | return (RREG32(DMA_RB_WPTR + sdma_offsets[me]) & 0x3fffc) >> 2; | ||
56 | } | ||
57 | |||
58 | static void si_dma_ring_set_wptr(struct amdgpu_ring *ring) | ||
59 | { | ||
60 | struct amdgpu_device *adev = ring->adev; | ||
61 | u32 me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1; | ||
62 | |||
63 | WREG32(DMA_RB_WPTR + sdma_offsets[me], (ring->wptr << 2) & 0x3fffc); | ||
64 | } | ||
65 | |||
66 | static void si_dma_ring_emit_ib(struct amdgpu_ring *ring, | ||
67 | struct amdgpu_ib *ib, | ||
68 | unsigned vm_id, bool ctx_switch) | ||
69 | { | ||
70 | /* The indirect buffer packet must end on an 8 DW boundary in the DMA ring. | ||
71 | * Pad as necessary with NOPs. | ||
72 | */ | ||
73 | while ((ring->wptr & 7) != 5) | ||
74 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0)); | ||
75 | amdgpu_ring_write(ring, DMA_IB_PACKET(DMA_PACKET_INDIRECT_BUFFER, vm_id, 0)); | ||
76 | amdgpu_ring_write(ring, (ib->gpu_addr & 0xFFFFFFE0)); | ||
77 | amdgpu_ring_write(ring, (ib->length_dw << 12) | (upper_32_bits(ib->gpu_addr) & 0xFF)); | ||
78 | |||
79 | } | ||
80 | |||
81 | static void si_dma_ring_emit_hdp_flush(struct amdgpu_ring *ring) | ||
82 | { | ||
83 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); | ||
84 | amdgpu_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL)); | ||
85 | amdgpu_ring_write(ring, 1); | ||
86 | } | ||
87 | |||
88 | static void si_dma_ring_emit_hdp_invalidate(struct amdgpu_ring *ring) | ||
89 | { | ||
90 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); | ||
91 | amdgpu_ring_write(ring, (0xf << 16) | (HDP_DEBUG0)); | ||
92 | amdgpu_ring_write(ring, 1); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * si_dma_ring_emit_fence - emit a fence on the DMA ring | ||
97 | * | ||
98 | * @ring: amdgpu ring pointer | ||
99 | * @fence: amdgpu fence object | ||
100 | * | ||
101 | * Add a DMA fence packet to the ring to write | ||
102 | * the fence seq number and DMA trap packet to generate | ||
103 | * an interrupt if needed (VI). | ||
104 | */ | ||
105 | static void si_dma_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, | ||
106 | unsigned flags) | ||
107 | { | ||
108 | |||
109 | bool write64bit = flags & AMDGPU_FENCE_FLAG_64BIT; | ||
110 | /* write the fence */ | ||
111 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0, 0)); | ||
112 | amdgpu_ring_write(ring, addr & 0xfffffffc); | ||
113 | amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xff)); | ||
114 | amdgpu_ring_write(ring, seq); | ||
115 | /* optionally write high bits as well */ | ||
116 | if (write64bit) { | ||
117 | addr += 4; | ||
118 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_FENCE, 0, 0, 0, 0)); | ||
119 | amdgpu_ring_write(ring, addr & 0xfffffffc); | ||
120 | amdgpu_ring_write(ring, (upper_32_bits(addr) & 0xff)); | ||
121 | amdgpu_ring_write(ring, upper_32_bits(seq)); | ||
122 | } | ||
123 | /* generate an interrupt */ | ||
124 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0, 0)); | ||
125 | } | ||
126 | |||
127 | static void si_dma_stop(struct amdgpu_device *adev) | ||
128 | { | ||
129 | struct amdgpu_ring *ring; | ||
130 | u32 rb_cntl; | ||
131 | unsigned i; | ||
132 | |||
133 | for (i = 0; i < adev->sdma.num_instances; i++) { | ||
134 | ring = &adev->sdma.instance[i].ring; | ||
135 | /* dma0 */ | ||
136 | rb_cntl = RREG32(DMA_RB_CNTL + sdma_offsets[i]); | ||
137 | rb_cntl &= ~DMA_RB_ENABLE; | ||
138 | WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl); | ||
139 | |||
140 | ring->ready = false; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static int si_dma_start(struct amdgpu_device *adev) | ||
145 | { | ||
146 | struct amdgpu_ring *ring; | ||
147 | u32 rb_cntl, dma_cntl, ib_cntl, rb_bufsz; | ||
148 | int i, r; | ||
149 | uint64_t rptr_addr; | ||
150 | |||
151 | for (i = 0; i < adev->sdma.num_instances; i++) { | ||
152 | ring = &adev->sdma.instance[i].ring; | ||
153 | |||
154 | WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL + sdma_offsets[i], 0); | ||
155 | WREG32(DMA_SEM_WAIT_FAIL_TIMER_CNTL + sdma_offsets[i], 0); | ||
156 | |||
157 | /* Set ring buffer size in dwords */ | ||
158 | rb_bufsz = order_base_2(ring->ring_size / 4); | ||
159 | rb_cntl = rb_bufsz << 1; | ||
160 | #ifdef __BIG_ENDIAN | ||
161 | rb_cntl |= DMA_RB_SWAP_ENABLE | DMA_RPTR_WRITEBACK_SWAP_ENABLE; | ||
162 | #endif | ||
163 | WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl); | ||
164 | |||
165 | /* Initialize the ring buffer's read and write pointers */ | ||
166 | WREG32(DMA_RB_RPTR + sdma_offsets[i], 0); | ||
167 | WREG32(DMA_RB_WPTR + sdma_offsets[i], 0); | ||
168 | |||
169 | rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4); | ||
170 | |||
171 | WREG32(DMA_RB_RPTR_ADDR_LO + sdma_offsets[i], lower_32_bits(rptr_addr)); | ||
172 | WREG32(DMA_RB_RPTR_ADDR_HI + sdma_offsets[i], upper_32_bits(rptr_addr) & 0xFF); | ||
173 | |||
174 | rb_cntl |= DMA_RPTR_WRITEBACK_ENABLE; | ||
175 | |||
176 | WREG32(DMA_RB_BASE + sdma_offsets[i], ring->gpu_addr >> 8); | ||
177 | |||
178 | /* enable DMA IBs */ | ||
179 | ib_cntl = DMA_IB_ENABLE | CMD_VMID_FORCE; | ||
180 | #ifdef __BIG_ENDIAN | ||
181 | ib_cntl |= DMA_IB_SWAP_ENABLE; | ||
182 | #endif | ||
183 | WREG32(DMA_IB_CNTL + sdma_offsets[i], ib_cntl); | ||
184 | |||
185 | dma_cntl = RREG32(DMA_CNTL + sdma_offsets[i]); | ||
186 | dma_cntl &= ~CTXEMPTY_INT_ENABLE; | ||
187 | WREG32(DMA_CNTL + sdma_offsets[i], dma_cntl); | ||
188 | |||
189 | ring->wptr = 0; | ||
190 | WREG32(DMA_RB_WPTR + sdma_offsets[i], ring->wptr << 2); | ||
191 | |||
192 | WREG32(DMA_RB_CNTL + sdma_offsets[i], rb_cntl | DMA_RB_ENABLE); | ||
193 | |||
194 | ring->ready = true; | ||
195 | |||
196 | r = amdgpu_ring_test_ring(ring); | ||
197 | if (r) { | ||
198 | ring->ready = false; | ||
199 | return r; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * si_dma_ring_test_ring - simple async dma engine test | ||
208 | * | ||
209 | * @ring: amdgpu_ring structure holding ring information | ||
210 | * | ||
211 | * Test the DMA engine by writing using it to write an | ||
212 | * value to memory. (VI). | ||
213 | * Returns 0 for success, error for failure. | ||
214 | */ | ||
215 | static int si_dma_ring_test_ring(struct amdgpu_ring *ring) | ||
216 | { | ||
217 | struct amdgpu_device *adev = ring->adev; | ||
218 | unsigned i; | ||
219 | unsigned index; | ||
220 | int r; | ||
221 | u32 tmp; | ||
222 | u64 gpu_addr; | ||
223 | |||
224 | r = amdgpu_wb_get(adev, &index); | ||
225 | if (r) { | ||
226 | dev_err(adev->dev, "(%d) failed to allocate wb slot\n", r); | ||
227 | return r; | ||
228 | } | ||
229 | |||
230 | gpu_addr = adev->wb.gpu_addr + (index * 4); | ||
231 | tmp = 0xCAFEDEAD; | ||
232 | adev->wb.wb[index] = cpu_to_le32(tmp); | ||
233 | |||
234 | r = amdgpu_ring_alloc(ring, 4); | ||
235 | if (r) { | ||
236 | DRM_ERROR("amdgpu: dma failed to lock ring %d (%d).\n", ring->idx, r); | ||
237 | amdgpu_wb_free(adev, index); | ||
238 | return r; | ||
239 | } | ||
240 | |||
241 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1)); | ||
242 | amdgpu_ring_write(ring, lower_32_bits(gpu_addr)); | ||
243 | amdgpu_ring_write(ring, upper_32_bits(gpu_addr) & 0xff); | ||
244 | amdgpu_ring_write(ring, 0xDEADBEEF); | ||
245 | amdgpu_ring_commit(ring); | ||
246 | |||
247 | for (i = 0; i < adev->usec_timeout; i++) { | ||
248 | tmp = le32_to_cpu(adev->wb.wb[index]); | ||
249 | if (tmp == 0xDEADBEEF) | ||
250 | break; | ||
251 | DRM_UDELAY(1); | ||
252 | } | ||
253 | |||
254 | if (i < adev->usec_timeout) { | ||
255 | DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i); | ||
256 | } else { | ||
257 | DRM_ERROR("amdgpu: ring %d test failed (0x%08X)\n", | ||
258 | ring->idx, tmp); | ||
259 | r = -EINVAL; | ||
260 | } | ||
261 | amdgpu_wb_free(adev, index); | ||
262 | |||
263 | return r; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * si_dma_ring_test_ib - test an IB on the DMA engine | ||
268 | * | ||
269 | * @ring: amdgpu_ring structure holding ring information | ||
270 | * | ||
271 | * Test a simple IB in the DMA ring (VI). | ||
272 | * Returns 0 on success, error on failure. | ||
273 | */ | ||
274 | static int si_dma_ring_test_ib(struct amdgpu_ring *ring, long timeout) | ||
275 | { | ||
276 | struct amdgpu_device *adev = ring->adev; | ||
277 | struct amdgpu_ib ib; | ||
278 | struct fence *f = NULL; | ||
279 | unsigned index; | ||
280 | u32 tmp = 0; | ||
281 | u64 gpu_addr; | ||
282 | long r; | ||
283 | |||
284 | r = amdgpu_wb_get(adev, &index); | ||
285 | if (r) { | ||
286 | dev_err(adev->dev, "(%ld) failed to allocate wb slot\n", r); | ||
287 | return r; | ||
288 | } | ||
289 | |||
290 | gpu_addr = adev->wb.gpu_addr + (index * 4); | ||
291 | tmp = 0xCAFEDEAD; | ||
292 | adev->wb.wb[index] = cpu_to_le32(tmp); | ||
293 | memset(&ib, 0, sizeof(ib)); | ||
294 | r = amdgpu_ib_get(adev, NULL, 256, &ib); | ||
295 | if (r) { | ||
296 | DRM_ERROR("amdgpu: failed to get ib (%ld).\n", r); | ||
297 | goto err0; | ||
298 | } | ||
299 | |||
300 | ib.ptr[0] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, 1); | ||
301 | ib.ptr[1] = lower_32_bits(gpu_addr); | ||
302 | ib.ptr[2] = upper_32_bits(gpu_addr) & 0xff; | ||
303 | ib.ptr[3] = 0xDEADBEEF; | ||
304 | ib.length_dw = 4; | ||
305 | r = amdgpu_ib_schedule(ring, 1, &ib, NULL, NULL, &f); | ||
306 | if (r) | ||
307 | goto err1; | ||
308 | |||
309 | r = fence_wait_timeout(f, false, timeout); | ||
310 | if (r == 0) { | ||
311 | DRM_ERROR("amdgpu: IB test timed out\n"); | ||
312 | r = -ETIMEDOUT; | ||
313 | goto err1; | ||
314 | } else if (r < 0) { | ||
315 | DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); | ||
316 | goto err1; | ||
317 | } | ||
318 | tmp = le32_to_cpu(adev->wb.wb[index]); | ||
319 | if (tmp == 0xDEADBEEF) { | ||
320 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx); | ||
321 | r = 0; | ||
322 | } else { | ||
323 | DRM_ERROR("amdgpu: ib test failed (0x%08X)\n", tmp); | ||
324 | r = -EINVAL; | ||
325 | } | ||
326 | |||
327 | err1: | ||
328 | amdgpu_ib_free(adev, &ib, NULL); | ||
329 | fence_put(f); | ||
330 | err0: | ||
331 | amdgpu_wb_free(adev, index); | ||
332 | return r; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * cik_dma_vm_copy_pte - update PTEs by copying them from the GART | ||
337 | * | ||
338 | * @ib: indirect buffer to fill with commands | ||
339 | * @pe: addr of the page entry | ||
340 | * @src: src addr to copy from | ||
341 | * @count: number of page entries to update | ||
342 | * | ||
343 | * Update PTEs by copying them from the GART using DMA (SI). | ||
344 | */ | ||
345 | static void si_dma_vm_copy_pte(struct amdgpu_ib *ib, | ||
346 | uint64_t pe, uint64_t src, | ||
347 | unsigned count) | ||
348 | { | ||
349 | unsigned bytes = count * 8; | ||
350 | |||
351 | ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, | ||
352 | 1, 0, 0, bytes); | ||
353 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); | ||
354 | ib->ptr[ib->length_dw++] = lower_32_bits(src); | ||
355 | ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; | ||
356 | ib->ptr[ib->length_dw++] = upper_32_bits(src) & 0xff; | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * si_dma_vm_write_pte - update PTEs by writing them manually | ||
361 | * | ||
362 | * @ib: indirect buffer to fill with commands | ||
363 | * @pe: addr of the page entry | ||
364 | * @value: dst addr to write into pe | ||
365 | * @count: number of page entries to update | ||
366 | * @incr: increase next addr by incr bytes | ||
367 | * | ||
368 | * Update PTEs by writing them manually using DMA (SI). | ||
369 | */ | ||
370 | static void si_dma_vm_write_pte(struct amdgpu_ib *ib, uint64_t pe, | ||
371 | uint64_t value, unsigned count, | ||
372 | uint32_t incr) | ||
373 | { | ||
374 | unsigned ndw = count * 2; | ||
375 | |||
376 | ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_WRITE, 0, 0, 0, ndw); | ||
377 | ib->ptr[ib->length_dw++] = lower_32_bits(pe); | ||
378 | ib->ptr[ib->length_dw++] = upper_32_bits(pe); | ||
379 | for (; ndw > 0; ndw -= 2) { | ||
380 | ib->ptr[ib->length_dw++] = lower_32_bits(value); | ||
381 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
382 | value += incr; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * si_dma_vm_set_pte_pde - update the page tables using sDMA | ||
388 | * | ||
389 | * @ib: indirect buffer to fill with commands | ||
390 | * @pe: addr of the page entry | ||
391 | * @addr: dst addr to write into pe | ||
392 | * @count: number of page entries to update | ||
393 | * @incr: increase next addr by incr bytes | ||
394 | * @flags: access flags | ||
395 | * | ||
396 | * Update the page tables using sDMA (CIK). | ||
397 | */ | ||
398 | static void si_dma_vm_set_pte_pde(struct amdgpu_ib *ib, | ||
399 | uint64_t pe, | ||
400 | uint64_t addr, unsigned count, | ||
401 | uint32_t incr, uint32_t flags) | ||
402 | { | ||
403 | uint64_t value; | ||
404 | unsigned ndw; | ||
405 | |||
406 | while (count) { | ||
407 | ndw = count * 2; | ||
408 | if (ndw > 0xFFFFE) | ||
409 | ndw = 0xFFFFE; | ||
410 | |||
411 | if (flags & AMDGPU_PTE_VALID) | ||
412 | value = addr; | ||
413 | else | ||
414 | value = 0; | ||
415 | |||
416 | /* for physically contiguous pages (vram) */ | ||
417 | ib->ptr[ib->length_dw++] = DMA_PTE_PDE_PACKET(ndw); | ||
418 | ib->ptr[ib->length_dw++] = pe; /* dst addr */ | ||
419 | ib->ptr[ib->length_dw++] = upper_32_bits(pe) & 0xff; | ||
420 | ib->ptr[ib->length_dw++] = flags; /* mask */ | ||
421 | ib->ptr[ib->length_dw++] = 0; | ||
422 | ib->ptr[ib->length_dw++] = value; /* value */ | ||
423 | ib->ptr[ib->length_dw++] = upper_32_bits(value); | ||
424 | ib->ptr[ib->length_dw++] = incr; /* increment size */ | ||
425 | ib->ptr[ib->length_dw++] = 0; | ||
426 | pe += ndw * 4; | ||
427 | addr += (ndw / 2) * incr; | ||
428 | count -= ndw / 2; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * si_dma_pad_ib - pad the IB to the required number of dw | ||
434 | * | ||
435 | * @ib: indirect buffer to fill with padding | ||
436 | * | ||
437 | */ | ||
438 | static void si_dma_ring_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib) | ||
439 | { | ||
440 | while (ib->length_dw & 0x7) | ||
441 | ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0); | ||
442 | } | ||
443 | |||
444 | /** | ||
445 | * cik_sdma_ring_emit_pipeline_sync - sync the pipeline | ||
446 | * | ||
447 | * @ring: amdgpu_ring pointer | ||
448 | * | ||
449 | * Make sure all previous operations are completed (CIK). | ||
450 | */ | ||
451 | static void si_dma_ring_emit_pipeline_sync(struct amdgpu_ring *ring) | ||
452 | { | ||
453 | uint32_t seq = ring->fence_drv.sync_seq; | ||
454 | uint64_t addr = ring->fence_drv.gpu_addr; | ||
455 | |||
456 | /* wait for idle */ | ||
457 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0) | | ||
458 | (1 << 27)); /* Poll memory */ | ||
459 | amdgpu_ring_write(ring, lower_32_bits(addr)); | ||
460 | amdgpu_ring_write(ring, (0xff << 16) | upper_32_bits(addr)); /* retry, addr_hi */ | ||
461 | amdgpu_ring_write(ring, 0xffffffff); /* mask */ | ||
462 | amdgpu_ring_write(ring, seq); /* value */ | ||
463 | amdgpu_ring_write(ring, (3 << 28) | 0x20); /* func(equal) | poll interval */ | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * si_dma_ring_emit_vm_flush - cik vm flush using sDMA | ||
468 | * | ||
469 | * @ring: amdgpu_ring pointer | ||
470 | * @vm: amdgpu_vm pointer | ||
471 | * | ||
472 | * Update the page table base and flush the VM TLB | ||
473 | * using sDMA (VI). | ||
474 | */ | ||
475 | static void si_dma_ring_emit_vm_flush(struct amdgpu_ring *ring, | ||
476 | unsigned vm_id, uint64_t pd_addr) | ||
477 | { | ||
478 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); | ||
479 | if (vm_id < 8) { | ||
480 | amdgpu_ring_write(ring, (0xf << 16) | (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + vm_id)); | ||
481 | } else { | ||
482 | amdgpu_ring_write(ring, (0xf << 16) | (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + (vm_id - 8))); | ||
483 | } | ||
484 | amdgpu_ring_write(ring, pd_addr >> 12); | ||
485 | |||
486 | /* bits 0-7 are the VM contexts0-7 */ | ||
487 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0)); | ||
488 | amdgpu_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST)); | ||
489 | amdgpu_ring_write(ring, 1 << vm_id); | ||
490 | |||
491 | /* wait for invalidate to complete */ | ||
492 | amdgpu_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0)); | ||
493 | amdgpu_ring_write(ring, VM_INVALIDATE_REQUEST); | ||
494 | amdgpu_ring_write(ring, 0xff << 16); /* retry */ | ||
495 | amdgpu_ring_write(ring, 1 << vm_id); /* mask */ | ||
496 | amdgpu_ring_write(ring, 0); /* value */ | ||
497 | amdgpu_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */ | ||
498 | } | ||
499 | |||
500 | static int si_dma_early_init(void *handle) | ||
501 | { | ||
502 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
503 | |||
504 | adev->sdma.num_instances = 2; | ||
505 | |||
506 | si_dma_set_ring_funcs(adev); | ||
507 | si_dma_set_buffer_funcs(adev); | ||
508 | si_dma_set_vm_pte_funcs(adev); | ||
509 | si_dma_set_irq_funcs(adev); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int si_dma_sw_init(void *handle) | ||
515 | { | ||
516 | struct amdgpu_ring *ring; | ||
517 | int r, i; | ||
518 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
519 | |||
520 | /* DMA0 trap event */ | ||
521 | r = amdgpu_irq_add_id(adev, 224, &adev->sdma.trap_irq); | ||
522 | if (r) | ||
523 | return r; | ||
524 | |||
525 | /* DMA1 trap event */ | ||
526 | r = amdgpu_irq_add_id(adev, 244, &adev->sdma.trap_irq_1); | ||
527 | if (r) | ||
528 | return r; | ||
529 | |||
530 | for (i = 0; i < adev->sdma.num_instances; i++) { | ||
531 | ring = &adev->sdma.instance[i].ring; | ||
532 | ring->ring_obj = NULL; | ||
533 | ring->use_doorbell = false; | ||
534 | sprintf(ring->name, "sdma%d", i); | ||
535 | r = amdgpu_ring_init(adev, ring, 1024, | ||
536 | DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0), 0xf, | ||
537 | &adev->sdma.trap_irq, | ||
538 | (i == 0) ? | ||
539 | AMDGPU_SDMA_IRQ_TRAP0 : AMDGPU_SDMA_IRQ_TRAP1, | ||
540 | AMDGPU_RING_TYPE_SDMA); | ||
541 | if (r) | ||
542 | return r; | ||
543 | } | ||
544 | |||
545 | return r; | ||
546 | } | ||
547 | |||
548 | static int si_dma_sw_fini(void *handle) | ||
549 | { | ||
550 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
551 | int i; | ||
552 | |||
553 | for (i = 0; i < adev->sdma.num_instances; i++) | ||
554 | amdgpu_ring_fini(&adev->sdma.instance[i].ring); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int si_dma_hw_init(void *handle) | ||
560 | { | ||
561 | int r; | ||
562 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
563 | |||
564 | r = si_dma_start(adev); | ||
565 | if (r) | ||
566 | return r; | ||
567 | |||
568 | return r; | ||
569 | } | ||
570 | |||
571 | static int si_dma_hw_fini(void *handle) | ||
572 | { | ||
573 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
574 | |||
575 | si_dma_stop(adev); | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static int si_dma_suspend(void *handle) | ||
581 | { | ||
582 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
583 | |||
584 | return si_dma_hw_fini(adev); | ||
585 | } | ||
586 | |||
587 | static int si_dma_resume(void *handle) | ||
588 | { | ||
589 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
590 | |||
591 | return si_dma_hw_init(adev); | ||
592 | } | ||
593 | |||
594 | static bool si_dma_is_idle(void *handle) | ||
595 | { | ||
596 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
597 | u32 tmp = RREG32(SRBM_STATUS2); | ||
598 | |||
599 | if (tmp & (DMA_BUSY_MASK | DMA1_BUSY_MASK)) | ||
600 | return false; | ||
601 | |||
602 | return true; | ||
603 | } | ||
604 | |||
605 | static int si_dma_wait_for_idle(void *handle) | ||
606 | { | ||
607 | unsigned i; | ||
608 | u32 tmp; | ||
609 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
610 | |||
611 | for (i = 0; i < adev->usec_timeout; i++) { | ||
612 | tmp = RREG32(SRBM_STATUS2) & (DMA_BUSY_MASK | DMA1_BUSY_MASK); | ||
613 | |||
614 | if (!tmp) | ||
615 | return 0; | ||
616 | udelay(1); | ||
617 | } | ||
618 | return -ETIMEDOUT; | ||
619 | } | ||
620 | |||
621 | static int si_dma_soft_reset(void *handle) | ||
622 | { | ||
623 | DRM_INFO("si_dma_soft_reset --- not implemented !!!!!!!\n"); | ||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static int si_dma_set_trap_irq_state(struct amdgpu_device *adev, | ||
628 | struct amdgpu_irq_src *src, | ||
629 | unsigned type, | ||
630 | enum amdgpu_interrupt_state state) | ||
631 | { | ||
632 | u32 sdma_cntl; | ||
633 | |||
634 | switch (type) { | ||
635 | case AMDGPU_SDMA_IRQ_TRAP0: | ||
636 | switch (state) { | ||
637 | case AMDGPU_IRQ_STATE_DISABLE: | ||
638 | sdma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET); | ||
639 | sdma_cntl &= ~TRAP_ENABLE; | ||
640 | WREG32(DMA_CNTL + DMA0_REGISTER_OFFSET, sdma_cntl); | ||
641 | break; | ||
642 | case AMDGPU_IRQ_STATE_ENABLE: | ||
643 | sdma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET); | ||
644 | sdma_cntl |= TRAP_ENABLE; | ||
645 | WREG32(DMA_CNTL + DMA0_REGISTER_OFFSET, sdma_cntl); | ||
646 | break; | ||
647 | default: | ||
648 | break; | ||
649 | } | ||
650 | break; | ||
651 | case AMDGPU_SDMA_IRQ_TRAP1: | ||
652 | switch (state) { | ||
653 | case AMDGPU_IRQ_STATE_DISABLE: | ||
654 | sdma_cntl = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET); | ||
655 | sdma_cntl &= ~TRAP_ENABLE; | ||
656 | WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, sdma_cntl); | ||
657 | break; | ||
658 | case AMDGPU_IRQ_STATE_ENABLE: | ||
659 | sdma_cntl = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET); | ||
660 | sdma_cntl |= TRAP_ENABLE; | ||
661 | WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, sdma_cntl); | ||
662 | break; | ||
663 | default: | ||
664 | break; | ||
665 | } | ||
666 | break; | ||
667 | default: | ||
668 | break; | ||
669 | } | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int si_dma_process_trap_irq(struct amdgpu_device *adev, | ||
674 | struct amdgpu_irq_src *source, | ||
675 | struct amdgpu_iv_entry *entry) | ||
676 | { | ||
677 | u8 instance_id, queue_id; | ||
678 | |||
679 | instance_id = (entry->ring_id & 0x3) >> 0; | ||
680 | queue_id = (entry->ring_id & 0xc) >> 2; | ||
681 | |||
682 | amdgpu_fence_process(&adev->sdma.instance[0].ring); | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int si_dma_process_trap_irq_1(struct amdgpu_device *adev, | ||
688 | struct amdgpu_irq_src *source, | ||
689 | struct amdgpu_iv_entry *entry) | ||
690 | { | ||
691 | u8 instance_id, queue_id; | ||
692 | |||
693 | instance_id = (entry->ring_id & 0x3) >> 0; | ||
694 | queue_id = (entry->ring_id & 0xc) >> 2; | ||
695 | |||
696 | amdgpu_fence_process(&adev->sdma.instance[1].ring); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int si_dma_process_illegal_inst_irq(struct amdgpu_device *adev, | ||
702 | struct amdgpu_irq_src *source, | ||
703 | struct amdgpu_iv_entry *entry) | ||
704 | { | ||
705 | DRM_ERROR("Illegal instruction in SDMA command stream\n"); | ||
706 | schedule_work(&adev->reset_work); | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | static int si_dma_set_clockgating_state(void *handle, | ||
711 | enum amd_clockgating_state state) | ||
712 | { | ||
713 | u32 orig, data, offset; | ||
714 | int i; | ||
715 | bool enable; | ||
716 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
717 | |||
718 | enable = (state == AMD_CG_STATE_GATE) ? true : false; | ||
719 | |||
720 | if (enable && (adev->cg_flags & AMD_CG_SUPPORT_SDMA_MGCG)) { | ||
721 | for (i = 0; i < adev->sdma.num_instances; i++) { | ||
722 | if (i == 0) | ||
723 | offset = DMA0_REGISTER_OFFSET; | ||
724 | else | ||
725 | offset = DMA1_REGISTER_OFFSET; | ||
726 | orig = data = RREG32(DMA_POWER_CNTL + offset); | ||
727 | data &= ~MEM_POWER_OVERRIDE; | ||
728 | if (data != orig) | ||
729 | WREG32(DMA_POWER_CNTL + offset, data); | ||
730 | WREG32(DMA_CLK_CTRL + offset, 0x00000100); | ||
731 | } | ||
732 | } else { | ||
733 | for (i = 0; i < adev->sdma.num_instances; i++) { | ||
734 | if (i == 0) | ||
735 | offset = DMA0_REGISTER_OFFSET; | ||
736 | else | ||
737 | offset = DMA1_REGISTER_OFFSET; | ||
738 | orig = data = RREG32(DMA_POWER_CNTL + offset); | ||
739 | data |= MEM_POWER_OVERRIDE; | ||
740 | if (data != orig) | ||
741 | WREG32(DMA_POWER_CNTL + offset, data); | ||
742 | |||
743 | orig = data = RREG32(DMA_CLK_CTRL + offset); | ||
744 | data = 0xff000000; | ||
745 | if (data != orig) | ||
746 | WREG32(DMA_CLK_CTRL + offset, data); | ||
747 | } | ||
748 | } | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int si_dma_set_powergating_state(void *handle, | ||
754 | enum amd_powergating_state state) | ||
755 | { | ||
756 | u32 tmp; | ||
757 | |||
758 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||
759 | |||
760 | WREG32(DMA_PGFSM_WRITE, 0x00002000); | ||
761 | WREG32(DMA_PGFSM_CONFIG, 0x100010ff); | ||
762 | |||
763 | for (tmp = 0; tmp < 5; tmp++) | ||
764 | WREG32(DMA_PGFSM_WRITE, 0); | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | const struct amd_ip_funcs si_dma_ip_funcs = { | ||
770 | .name = "si_dma", | ||
771 | .early_init = si_dma_early_init, | ||
772 | .late_init = NULL, | ||
773 | .sw_init = si_dma_sw_init, | ||
774 | .sw_fini = si_dma_sw_fini, | ||
775 | .hw_init = si_dma_hw_init, | ||
776 | .hw_fini = si_dma_hw_fini, | ||
777 | .suspend = si_dma_suspend, | ||
778 | .resume = si_dma_resume, | ||
779 | .is_idle = si_dma_is_idle, | ||
780 | .wait_for_idle = si_dma_wait_for_idle, | ||
781 | .soft_reset = si_dma_soft_reset, | ||
782 | .set_clockgating_state = si_dma_set_clockgating_state, | ||
783 | .set_powergating_state = si_dma_set_powergating_state, | ||
784 | }; | ||
785 | |||
786 | static const struct amdgpu_ring_funcs si_dma_ring_funcs = { | ||
787 | .get_rptr = si_dma_ring_get_rptr, | ||
788 | .get_wptr = si_dma_ring_get_wptr, | ||
789 | .set_wptr = si_dma_ring_set_wptr, | ||
790 | .parse_cs = NULL, | ||
791 | .emit_ib = si_dma_ring_emit_ib, | ||
792 | .emit_fence = si_dma_ring_emit_fence, | ||
793 | .emit_pipeline_sync = si_dma_ring_emit_pipeline_sync, | ||
794 | .emit_vm_flush = si_dma_ring_emit_vm_flush, | ||
795 | .emit_hdp_flush = si_dma_ring_emit_hdp_flush, | ||
796 | .emit_hdp_invalidate = si_dma_ring_emit_hdp_invalidate, | ||
797 | .test_ring = si_dma_ring_test_ring, | ||
798 | .test_ib = si_dma_ring_test_ib, | ||
799 | .insert_nop = amdgpu_ring_insert_nop, | ||
800 | .pad_ib = si_dma_ring_pad_ib, | ||
801 | }; | ||
802 | |||
803 | static void si_dma_set_ring_funcs(struct amdgpu_device *adev) | ||
804 | { | ||
805 | int i; | ||
806 | |||
807 | for (i = 0; i < adev->sdma.num_instances; i++) | ||
808 | adev->sdma.instance[i].ring.funcs = &si_dma_ring_funcs; | ||
809 | } | ||
810 | |||
811 | static const struct amdgpu_irq_src_funcs si_dma_trap_irq_funcs = { | ||
812 | .set = si_dma_set_trap_irq_state, | ||
813 | .process = si_dma_process_trap_irq, | ||
814 | }; | ||
815 | |||
816 | static const struct amdgpu_irq_src_funcs si_dma_trap_irq_funcs_1 = { | ||
817 | .set = si_dma_set_trap_irq_state, | ||
818 | .process = si_dma_process_trap_irq_1, | ||
819 | }; | ||
820 | |||
821 | static const struct amdgpu_irq_src_funcs si_dma_illegal_inst_irq_funcs = { | ||
822 | .process = si_dma_process_illegal_inst_irq, | ||
823 | }; | ||
824 | |||
825 | static void si_dma_set_irq_funcs(struct amdgpu_device *adev) | ||
826 | { | ||
827 | adev->sdma.trap_irq.num_types = AMDGPU_SDMA_IRQ_LAST; | ||
828 | adev->sdma.trap_irq.funcs = &si_dma_trap_irq_funcs; | ||
829 | adev->sdma.trap_irq_1.funcs = &si_dma_trap_irq_funcs_1; | ||
830 | adev->sdma.illegal_inst_irq.funcs = &si_dma_illegal_inst_irq_funcs; | ||
831 | } | ||
832 | |||
833 | /** | ||
834 | * si_dma_emit_copy_buffer - copy buffer using the sDMA engine | ||
835 | * | ||
836 | * @ring: amdgpu_ring structure holding ring information | ||
837 | * @src_offset: src GPU address | ||
838 | * @dst_offset: dst GPU address | ||
839 | * @byte_count: number of bytes to xfer | ||
840 | * | ||
841 | * Copy GPU buffers using the DMA engine (VI). | ||
842 | * Used by the amdgpu ttm implementation to move pages if | ||
843 | * registered as the asic copy callback. | ||
844 | */ | ||
845 | static void si_dma_emit_copy_buffer(struct amdgpu_ib *ib, | ||
846 | uint64_t src_offset, | ||
847 | uint64_t dst_offset, | ||
848 | uint32_t byte_count) | ||
849 | { | ||
850 | ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_COPY, | ||
851 | 1, 0, 0, byte_count); | ||
852 | ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); | ||
853 | ib->ptr[ib->length_dw++] = lower_32_bits(src_offset); | ||
854 | ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset) & 0xff; | ||
855 | ib->ptr[ib->length_dw++] = upper_32_bits(src_offset) & 0xff; | ||
856 | } | ||
857 | |||
858 | /** | ||
859 | * si_dma_emit_fill_buffer - fill buffer using the sDMA engine | ||
860 | * | ||
861 | * @ring: amdgpu_ring structure holding ring information | ||
862 | * @src_data: value to write to buffer | ||
863 | * @dst_offset: dst GPU address | ||
864 | * @byte_count: number of bytes to xfer | ||
865 | * | ||
866 | * Fill GPU buffers using the DMA engine (VI). | ||
867 | */ | ||
868 | static void si_dma_emit_fill_buffer(struct amdgpu_ib *ib, | ||
869 | uint32_t src_data, | ||
870 | uint64_t dst_offset, | ||
871 | uint32_t byte_count) | ||
872 | { | ||
873 | ib->ptr[ib->length_dw++] = DMA_PACKET(DMA_PACKET_CONSTANT_FILL, | ||
874 | 0, 0, 0, byte_count / 4); | ||
875 | ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); | ||
876 | ib->ptr[ib->length_dw++] = src_data; | ||
877 | ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset) << 16; | ||
878 | } | ||
879 | |||
880 | |||
881 | static const struct amdgpu_buffer_funcs si_dma_buffer_funcs = { | ||
882 | .copy_max_bytes = 0xffff8, | ||
883 | .copy_num_dw = 5, | ||
884 | .emit_copy_buffer = si_dma_emit_copy_buffer, | ||
885 | |||
886 | .fill_max_bytes = 0xffff8, | ||
887 | .fill_num_dw = 4, | ||
888 | .emit_fill_buffer = si_dma_emit_fill_buffer, | ||
889 | }; | ||
890 | |||
891 | static void si_dma_set_buffer_funcs(struct amdgpu_device *adev) | ||
892 | { | ||
893 | if (adev->mman.buffer_funcs == NULL) { | ||
894 | adev->mman.buffer_funcs = &si_dma_buffer_funcs; | ||
895 | adev->mman.buffer_funcs_ring = &adev->sdma.instance[0].ring; | ||
896 | } | ||
897 | } | ||
898 | |||
899 | static const struct amdgpu_vm_pte_funcs si_dma_vm_pte_funcs = { | ||
900 | .copy_pte = si_dma_vm_copy_pte, | ||
901 | .write_pte = si_dma_vm_write_pte, | ||
902 | .set_pte_pde = si_dma_vm_set_pte_pde, | ||
903 | }; | ||
904 | |||
905 | static void si_dma_set_vm_pte_funcs(struct amdgpu_device *adev) | ||
906 | { | ||
907 | unsigned i; | ||
908 | |||
909 | if (adev->vm_manager.vm_pte_funcs == NULL) { | ||
910 | adev->vm_manager.vm_pte_funcs = &si_dma_vm_pte_funcs; | ||
911 | for (i = 0; i < adev->sdma.num_instances; i++) | ||
912 | adev->vm_manager.vm_pte_rings[i] = | ||
913 | &adev->sdma.instance[i].ring; | ||
914 | |||
915 | adev->vm_manager.vm_pte_num_rings = adev->sdma.num_instances; | ||
916 | } | ||
917 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.h b/drivers/gpu/drm/amd/amdgpu/si_dma.h new file mode 100644 index 000000000000..3a3e0c78a54b --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/si_dma.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Advanced Micro Devices, Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __SI_DMA_H__ | ||
25 | #define __SI_DMA_H__ | ||
26 | |||
27 | extern const struct amd_ip_funcs si_dma_ip_funcs; | ||
28 | |||
29 | #endif | ||