Skip to content

Commit 112d65a

Browse files
Ben Skeggsgregkh
authored andcommitted
drm/nouveau/disp: fix DP disable race
[ Upstream commit e04cfdc ] If a HPD pulse signalling the need to retrain the link occurs between the KMS driver releasing the output and the supervisor interrupt that finishes the teardown, it was possible get a NULL-ptr deref. Avoid this by marking the link as inactive earlier. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 1a255bf commit 112d65a

4 files changed

Lines changed: 19 additions & 9 deletions

File tree

drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -412,14 +412,10 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
412412
}
413413

414414
static void
415-
nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior)
415+
nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
416416
{
417417
struct nvkm_dp *dp = nvkm_dp(outp);
418418

419-
/* Prevent link from being retrained if sink sends an IRQ. */
420-
atomic_set(&dp->lt.done, 0);
421-
ior->dp.nr = 0;
422-
423419
/* Execute DisableLT script from DP Info Table. */
424420
nvbios_init(&ior->disp->engine.subdev, dp->info.script[4],
425421
init.outp = &dp->outp.info;
@@ -428,6 +424,16 @@ nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior)
428424
);
429425
}
430426

427+
static void
428+
nvkm_dp_release(struct nvkm_outp *outp)
429+
{
430+
struct nvkm_dp *dp = nvkm_dp(outp);
431+
432+
/* Prevent link from being retrained if sink sends an IRQ. */
433+
atomic_set(&dp->lt.done, 0);
434+
dp->outp.ior->dp.nr = 0;
435+
}
436+
431437
static int
432438
nvkm_dp_acquire(struct nvkm_outp *outp)
433439
{
@@ -576,6 +582,7 @@ nvkm_dp_func = {
576582
.fini = nvkm_dp_fini,
577583
.acquire = nvkm_dp_acquire,
578584
.release = nvkm_dp_release,
585+
.disable = nvkm_dp_disable,
579586
};
580587

581588
static int

drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,11 +436,11 @@ nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head)
436436
nv50_disp_super_ied_off(head, ior, 2);
437437

438438
/* If we're shutting down the OR's only active head, execute
439-
* the output path's release function.
439+
* the output path's disable function.
440440
*/
441441
if (ior->arm.head == (1 << head->id)) {
442-
if ((outp = ior->arm.outp) && outp->func->release)
443-
outp->func->release(outp, ior);
442+
if ((outp = ior->arm.outp) && outp->func->disable)
443+
outp->func->disable(outp, ior);
444444
}
445445
}
446446

drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ nvkm_outp_release(struct nvkm_outp *outp, u8 user)
9393
if (ior) {
9494
outp->acquired &= ~user;
9595
if (!outp->acquired) {
96+
if (outp->func->release && outp->ior)
97+
outp->func->release(outp);
9698
outp->ior->asy.outp = NULL;
9799
outp->ior = NULL;
98100
}

drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ struct nvkm_outp_func {
4141
void (*init)(struct nvkm_outp *);
4242
void (*fini)(struct nvkm_outp *);
4343
int (*acquire)(struct nvkm_outp *);
44-
void (*release)(struct nvkm_outp *, struct nvkm_ior *);
44+
void (*release)(struct nvkm_outp *);
45+
void (*disable)(struct nvkm_outp *, struct nvkm_ior *);
4546
};
4647

4748
#define OUTP_MSG(o,l,f,a...) do { \

0 commit comments

Comments
 (0)