Skip to content

Commit 38b2fd2

Browse files
AaronDotopsiff
authored andcommitted
drm/amdgpu: Fix pcie order dislocation
Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn> Signed-off-by: Hongchen Zhang <zhanghongchen@loongson.cn> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> (cherry picked from commit bcaf362) Signed-off-by: Wentao Guan <guanwentao@uniontech.com> Conflicts: drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h
1 parent c48aea9 commit 38b2fd2

5 files changed

Lines changed: 172 additions & 0 deletions

File tree

drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,11 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
12891289
uint64_t seq;
12901290
int r;
12911291

1292+
#ifdef CONFIG_LOONGARCH
1293+
while (amdgpu_ih_fix_is_busy(p->adev))
1294+
msleep(20);
1295+
#endif
1296+
12921297
for (i = 0; i < p->gang_size; ++i)
12931298
drm_sched_job_arm(&p->jobs[i]->base);
12941299

drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#include "amdgpu_ih.h"
2828
#include "amdgpu_reset.h"
2929

30+
#ifdef CONFIG_LOONGARCH
31+
static void amdgpu_ih_handle_fix_work(struct work_struct *work);
32+
#endif
33+
3034
/**
3135
* amdgpu_ih_ring_init - initialize the IH state
3236
*
@@ -72,6 +76,15 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
7276
ih->wptr_cpu = &ih->ring[ih->ring_size / 4];
7377
ih->rptr_addr = dma_addr + ih->ring_size + 4;
7478
ih->rptr_cpu = &ih->ring[(ih->ring_size / 4) + 1];
79+
80+
#ifdef CONFIG_LOONGARCH
81+
INIT_WORK(&adev->irq.ih.fix_work, amdgpu_ih_handle_fix_work);
82+
for (r = 0; r < (adev->irq.ih.ring_size >> 2); r++)
83+
adev->irq.ih.ring[r] = 0xDEADBEFF;
84+
/* memory barrier for writing into ih ring */
85+
mb();
86+
#endif
87+
7588
} else {
7689
unsigned wptr_offs, rptr_offs;
7790

@@ -99,6 +112,15 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
99112
ih->wptr_cpu = &adev->wb.wb[wptr_offs];
100113
ih->rptr_addr = adev->wb.gpu_addr + rptr_offs * 4;
101114
ih->rptr_cpu = &adev->wb.wb[rptr_offs];
115+
116+
#ifdef CONFIG_LOONGARCH
117+
INIT_WORK(&adev->irq.ih.fix_work, amdgpu_ih_handle_fix_work);
118+
for (r = 0; r < (adev->irq.ih.ring_size >> 2); r++)
119+
adev->irq.ih.ring[r] = 0xDEADBEFF;
120+
/* memory barrier for writing into ih ring */
121+
mb();
122+
#endif
123+
102124
}
103125

104126
init_waitqueue_head(&ih->wait_process);
@@ -120,6 +142,10 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
120142
if (!ih->ring)
121143
return;
122144

145+
#ifdef CONFIG_LOONGARCH
146+
cancel_work_sync(&adev->irq.ih.fix_work);
147+
#endif
148+
123149
if (ih->use_bus_addr) {
124150

125151
/* add 8 bytes for the rptr/wptr shadows and
@@ -136,6 +162,113 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
136162
}
137163
}
138164

165+
#ifdef CONFIG_LOONGARCH
166+
167+
int amdgpu_ih_fix_is_busy(struct amdgpu_device *adev)
168+
{
169+
return atomic_read(&adev->irq.cs_lock);
170+
}
171+
172+
static int amdgpu_ih_fix_loongarch_pcie_order_start(struct amdgpu_ih_ring *ih,
173+
u32 rptr, u32 wptr,
174+
bool forever)
175+
{
176+
int i;
177+
int check_cnt = 0;
178+
u32 ring_end = ih->ring_size >> 2;
179+
180+
if (rptr == wptr)
181+
return 0;
182+
183+
rptr = rptr >> 2;
184+
wptr = wptr >> 2;
185+
186+
wptr = (rptr > wptr) ? ring_end : wptr;
187+
188+
restart_check:
189+
if (!forever && ++check_cnt > 1)
190+
return -ENAVAIL;
191+
192+
if (forever)
193+
msleep(20);
194+
195+
for (i = rptr; i < wptr; i += 1) {
196+
if (le32_to_cpu(ih->ring[i]) == 0xDEADBEFF)
197+
goto restart_check;
198+
}
199+
200+
if (rptr > wptr) {
201+
for (i = 0; i < wptr; i += 1) {
202+
if (le32_to_cpu(ih->ring[i]) == 0xDEADBEFF)
203+
goto restart_check;
204+
}
205+
}
206+
207+
return 0;
208+
}
209+
210+
static int amdgpu_ih_fix_loongarch_pcie_order_end(struct amdgpu_ih_ring *ih,
211+
u32 rptr, u32 wptr)
212+
{
213+
int i;
214+
u32 ring_end = ih->ring_size >> 2;
215+
216+
if (rptr == wptr)
217+
return 0;
218+
219+
rptr = rptr >> 2;
220+
wptr = wptr >> 2;
221+
222+
wptr = (rptr > wptr) ? ring_end : wptr;
223+
224+
for (i = rptr; i < wptr; i += 1)
225+
ih->ring[i] = 0xDEADBEFF;
226+
227+
if (rptr > wptr) {
228+
for (i = 0; i < wptr; i += 1)
229+
ih->ring[i] = 0xDEADBEFF;
230+
}
231+
/* memory barrier for writing into ih ring */
232+
mb();
233+
return 0;
234+
}
235+
236+
static void amdgpu_ih_handle_fix_work(struct work_struct *work)
237+
{
238+
struct amdgpu_device *adev =
239+
container_of(work, struct amdgpu_device, irq.ih.fix_work);
240+
struct amdgpu_ih_ring *ih = &adev->irq.ih;
241+
242+
u32 wptr;
243+
u32 old_rptr;
244+
245+
restart:
246+
247+
wptr = amdgpu_ih_get_wptr(adev, ih);
248+
/* Order reading of wptr vs. reading of IH ring data */
249+
rmb();
250+
251+
old_rptr = ih->rptr;
252+
amdgpu_ih_fix_loongarch_pcie_order_start(&adev->irq.ih, old_rptr, wptr, true);
253+
254+
while (adev->irq.ih.rptr != wptr) {
255+
amdgpu_irq_dispatch(adev, ih);
256+
ih->rptr &= ih->ptr_mask;
257+
}
258+
259+
amdgpu_ih_fix_loongarch_pcie_order_end(&adev->irq.ih, old_rptr, adev->irq.ih.rptr);
260+
261+
amdgpu_ih_set_rptr(adev, ih);
262+
/* memory barrier for setting rptr */
263+
mb();
264+
265+
if (ih->rptr != amdgpu_ih_get_wptr(adev, ih))
266+
goto restart;
267+
268+
atomic_set(&adev->irq.cs_lock, 0);
269+
}
270+
#endif
271+
139272
/**
140273
* amdgpu_ih_ring_write - write IV to the ring buffer
141274
*
@@ -210,6 +343,10 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
210343
{
211344
unsigned int count;
212345
u32 wptr;
346+
#ifdef CONFIG_LOONGARCH
347+
u32 old_rptr;
348+
int r;
349+
#endif
213350

214351
if (!ih->enabled || adev->shutdown)
215352
return IRQ_NONE;
@@ -223,11 +360,28 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
223360
/* Order reading of wptr vs. reading of IH ring data */
224361
rmb();
225362

363+
#ifdef CONFIG_LOONGARCH
364+
old_rptr = adev->irq.ih.rptr;
365+
r = amdgpu_ih_fix_loongarch_pcie_order_start(&adev->irq.ih, old_rptr, wptr, false);
366+
if (r) {
367+
if (old_rptr == ((wptr + 16) & adev->irq.ih.ptr_mask))
368+
return IRQ_NONE;
369+
370+
atomic_xchg(&adev->irq.cs_lock, 1);
371+
schedule_work(&adev->irq.ih.fix_work);
372+
return IRQ_NONE;
373+
}
374+
#endif
375+
226376
while (ih->rptr != wptr && --count) {
227377
amdgpu_irq_dispatch(adev, ih);
228378
ih->rptr &= ih->ptr_mask;
229379
}
230380

381+
#ifdef CONFIG_LOONGARCH
382+
amdgpu_ih_fix_loongarch_pcie_order_end(&adev->irq.ih, old_rptr, adev->irq.ih.rptr);
383+
#endif
384+
231385
if (!ih->overflow)
232386
amdgpu_ih_set_rptr(adev, ih);
233387

drivers/gpu/drm/amd/amdgpu/amdgpu_ih.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ struct amdgpu_ih_ring {
7373
wait_queue_head_t wait_process;
7474
uint64_t processed_timestamp;
7575
bool overflow;
76+
#ifdef CONFIG_LOONGARCH
77+
struct work_struct fix_work;
78+
#endif
7679
};
7780

7881
/* return true if time stamp t2 is after t1 with 48bit wrap around */
@@ -115,4 +118,7 @@ void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
115118
uint64_t amdgpu_ih_decode_iv_ts_helper(struct amdgpu_ih_ring *ih, u32 rptr,
116119
signed int offset);
117120
const char *amdgpu_ih_ring_name(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
121+
#ifdef CONFIG_LOONGARCH
122+
int amdgpu_ih_fix_is_busy(struct amdgpu_device *adev);
123+
#endif
118124
#endif

drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
276276

277277
spin_lock_init(&adev->irq.lock);
278278

279+
#ifdef CONFIG_LOONGARCH
280+
atomic_set(&adev->irq.cs_lock, 0);
281+
#endif
282+
279283
/* Enable MSI if not disabled by module parameter */
280284
adev->irq.msi_enabled = false;
281285

drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ struct amdgpu_irq {
100100
uint32_t srbm_soft_reset;
101101
u32 retry_cam_doorbell_index;
102102
bool retry_cam_enabled;
103+
#ifdef CONFIG_LOONGARCH
104+
atomic_t cs_lock;
105+
#endif
103106
};
104107

105108
enum interrupt_node_id_per_aid {

0 commit comments

Comments
 (0)