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_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_wb_get(adev, &adev->irq.ih.rptr_offs);
102 if (r) {
103 amdgpu_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_wb_free(adev, adev->irq.ih.wptr_offs);
137 amdgpu_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 amdgpu_amdkfd_interrupt(adev,
174 (const void *) &adev->irq.ih.ring[ring_index]);
175
176 entry.iv_entry = (const uint32_t *)
177 &adev->irq.ih.ring[ring_index];
178 amdgpu_ih_decode_iv(adev, &entry);
179 adev->irq.ih.rptr &= adev->irq.ih.ptr_mask;
180
181 amdgpu_irq_dispatch(adev, &entry);
182 }
183 amdgpu_ih_set_rptr(adev);
184 atomic_set(&adev->irq.ih.lock, 0);
185
186
187 wptr = amdgpu_ih_get_wptr(adev);
188 if (wptr != adev->irq.ih.rptr)
189 goto restart_ih;
190
191 return IRQ_HANDLED;
192}
193