Skip to content

Commit 82eaa05

Browse files
wuqianhaiopsiff
authored andcommitted
drm/amdgpu: Fix kernel deadlock for missing code
Add the missing code when migrating this patch from 4.19 which can cause kernel deadlock. Fixes: bcaf362 (drm/amdgpu: Fix pcie order dislocation) Signed-off-by: wuqianhai <wuqianhai@loongson.cn> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> (cherry picked from commit 98acedf) Signed-off-by: Wentao Guan <guanwentao@uniontech.com> Conflicts: drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c
1 parent 20f9d9c commit 82eaa05

2 files changed

Lines changed: 52 additions & 34 deletions

File tree

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

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,6 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
7777
ih->rptr_addr = dma_addr + ih->ring_size + 4;
7878
ih->rptr_cpu = &ih->ring[(ih->ring_size / 4) + 1];
7979

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
8780

8881
} else {
8982
unsigned wptr_offs, rptr_offs;
@@ -113,16 +106,17 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
113106
ih->rptr_addr = adev->wb.gpu_addr + rptr_offs * 4;
114107
ih->rptr_cpu = &adev->wb.wb[rptr_offs];
115108

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-
124109
}
125110

111+
#ifdef CONFIG_LOONGARCH
112+
INIT_WORK(&ih->fix_work, amdgpu_ih_handle_fix_work);
113+
ih->adev = adev;
114+
atomic_set(&ih->lock, 0);
115+
for (r = 0; r < (ih->ring_size >> 2); r++)
116+
ih->ring[r] = 0xDEADBEFF;
117+
/* ensure data active */
118+
mb();
119+
#endif
126120
init_waitqueue_head(&ih->wait_process);
127121
return 0;
128122
}
@@ -143,7 +137,7 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
143137
return;
144138

145139
#ifdef CONFIG_LOONGARCH
146-
cancel_work_sync(&adev->irq.ih.fix_work);
140+
cancel_work_sync(&ih->fix_work);
147141
#endif
148142

149143
if (ih->use_bus_addr) {
@@ -173,7 +167,7 @@ static int amdgpu_ih_fix_loongarch_pcie_order_start(struct amdgpu_ih_ring *ih,
173167
u32 rptr, u32 wptr,
174168
bool forever)
175169
{
176-
int i;
170+
int i, j;
177171
int check_cnt = 0;
178172
u32 ring_end = ih->ring_size >> 2;
179173

@@ -193,13 +187,19 @@ static int amdgpu_ih_fix_loongarch_pcie_order_start(struct amdgpu_ih_ring *ih,
193187
msleep(20);
194188

195189
for (i = rptr; i < wptr; i += 1) {
196-
if (le32_to_cpu(ih->ring[i]) == 0xDEADBEFF && (i % 4) != 3)
190+
j = i + 1;
191+
j = (j < wptr) ? j : rptr;
192+
if (le32_to_cpu(ih->ring[i]) == 0xDEADBEFF &&
193+
le32_to_cpu(ih->ring[j]) == 0xDEADBEFF)
197194
goto restart_check;
198195
}
199196

200197
if (rptr > wptr) {
201198
for (i = 0; i < wptr; i += 1) {
202-
if (le32_to_cpu(ih->ring[i]) == 0xDEADBEFF && (i % 4) != 3)
199+
j = i + 1;
200+
j = (j < wptr) ? j : 0;
201+
if (le32_to_cpu(ih->ring[i]) == 0xDEADBEFF &&
202+
le32_to_cpu(ih->ring[j]) == 0xDEADBEFF)
203203
goto restart_check;
204204
}
205205
}
@@ -235,35 +235,42 @@ static int amdgpu_ih_fix_loongarch_pcie_order_end(struct amdgpu_ih_ring *ih,
235235

236236
static void amdgpu_ih_handle_fix_work(struct work_struct *work)
237237
{
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;
238+
struct amdgpu_ih_ring *ih =
239+
container_of(work, struct amdgpu_ih_ring, fix_work);
240+
struct amdgpu_device *adev = ih->adev;
241241

242242
u32 wptr;
243243
u32 old_rptr;
244+
int restart_fg = 0;
244245

245246
restart:
247+
if (restart_fg && atomic_xchg(&ih->lock, 1)) {
248+
atomic_set(&adev->irq.cs_lock, 0);
249+
return;
250+
}
246251

247252
wptr = amdgpu_ih_get_wptr(adev, ih);
248253
/* Order reading of wptr vs. reading of IH ring data */
249254
rmb();
250255

251256
old_rptr = ih->rptr;
252-
amdgpu_ih_fix_loongarch_pcie_order_start(&adev->irq.ih, old_rptr, wptr, true);
257+
amdgpu_ih_fix_loongarch_pcie_order_start(ih, old_rptr, wptr, true);
253258

254-
while (adev->irq.ih.rptr != wptr) {
259+
while (ih->rptr != wptr) {
255260
amdgpu_irq_dispatch(adev, ih);
256261
ih->rptr &= ih->ptr_mask;
257262
}
258263

259-
amdgpu_ih_fix_loongarch_pcie_order_end(&adev->irq.ih, old_rptr, adev->irq.ih.rptr);
264+
amdgpu_ih_fix_loongarch_pcie_order_end(ih, old_rptr, ih->rptr);
260265

261266
amdgpu_ih_set_rptr(adev, ih);
262-
/* memory barrier for setting rptr */
267+
atomic_set(&ih->lock, 0);
263268
mb();
264269

265-
if (ih->rptr != amdgpu_ih_get_wptr(adev, ih))
270+
if (ih->rptr != amdgpu_ih_get_wptr(adev, ih)) {
271+
restart_fg = 1;
266272
goto restart;
273+
}
267274

268275
atomic_set(&adev->irq.cs_lock, 0);
269276
}
@@ -354,22 +361,28 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
354361
wptr = amdgpu_ih_get_wptr(adev, ih);
355362

356363
restart_ih:
364+
#ifdef CONFIG_LOONGARCH
365+
/* is somebody else already processing irqs? */
366+
if (atomic_xchg(&ih->lock, 1))
367+
return IRQ_NONE;
368+
#endif
357369
count = AMDGPU_IH_MAX_NUM_IVS;
358370
dev_dbg(adev->dev, "%s: rptr %d, wptr %d\n", __func__, ih->rptr, wptr);
359371

360372
/* Order reading of wptr vs. reading of IH ring data */
361373
rmb();
362374

363375
#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);
376+
old_rptr = ih->rptr;
377+
r = amdgpu_ih_fix_loongarch_pcie_order_start(ih, old_rptr, wptr, false);
366378
if (r) {
367-
if (old_rptr == ((wptr + 16) & adev->irq.ih.ptr_mask) ||
368-
old_rptr == ((wptr + 32) & adev->irq.ih.ptr_mask))
379+
if (old_rptr == ((wptr + 16) & ih->ptr_mask) ||
380+
old_rptr == ((wptr + 32) & ih->ptr_mask)) {
381+
atomic_set(&ih->lock, 0);
369382
return IRQ_NONE;
370-
383+
}
371384
atomic_xchg(&adev->irq.cs_lock, 1);
372-
schedule_work(&adev->irq.ih.fix_work);
385+
schedule_work(&ih->fix_work);
373386
return IRQ_NONE;
374387
}
375388
#endif
@@ -380,12 +393,15 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
380393
}
381394

382395
#ifdef CONFIG_LOONGARCH
383-
amdgpu_ih_fix_loongarch_pcie_order_end(&adev->irq.ih, old_rptr, adev->irq.ih.rptr);
396+
amdgpu_ih_fix_loongarch_pcie_order_end(ih, old_rptr, ih->rptr);
384397
#endif
385398

386399
if (!ih->overflow)
387400
amdgpu_ih_set_rptr(adev, ih);
388401

402+
#ifdef CONFIG_LOONGARCH
403+
atomic_set(&ih->lock, 0);
404+
#endif
389405
wake_up_all(&ih->wait_process);
390406

391407
/* make sure wptr hasn't changed while processing */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ struct amdgpu_ih_ring {
7474
uint64_t processed_timestamp;
7575
bool overflow;
7676
#ifdef CONFIG_LOONGARCH
77+
atomic_t lock;
7778
struct work_struct fix_work;
79+
struct amdgpu_device *adev;
7880
#endif
7981
};
8082

0 commit comments

Comments
 (0)