drm/nouveau/disp: fix DP disable race
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>
This commit is contained in:
parent
f6d52b2172
commit
e04cfdc9b7
|
@ -413,14 +413,10 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
|
|||
}
|
||||
|
||||
static void
|
||||
nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior)
|
||||
nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
|
||||
{
|
||||
struct nvkm_dp *dp = nvkm_dp(outp);
|
||||
|
||||
/* Prevent link from being retrained if sink sends an IRQ. */
|
||||
atomic_set(&dp->lt.done, 0);
|
||||
ior->dp.nr = 0;
|
||||
|
||||
/* Execute DisableLT script from DP Info Table. */
|
||||
nvbios_init(&ior->disp->engine.subdev, dp->info.script[4],
|
||||
init.outp = &dp->outp.info;
|
||||
|
@ -429,6 +425,16 @@ nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior)
|
|||
);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_dp_release(struct nvkm_outp *outp)
|
||||
{
|
||||
struct nvkm_dp *dp = nvkm_dp(outp);
|
||||
|
||||
/* Prevent link from being retrained if sink sends an IRQ. */
|
||||
atomic_set(&dp->lt.done, 0);
|
||||
dp->outp.ior->dp.nr = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvkm_dp_acquire(struct nvkm_outp *outp)
|
||||
{
|
||||
|
@ -607,6 +613,7 @@ nvkm_dp_func = {
|
|||
.fini = nvkm_dp_fini,
|
||||
.acquire = nvkm_dp_acquire,
|
||||
.release = nvkm_dp_release,
|
||||
.disable = nvkm_dp_disable,
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
|
@ -501,11 +501,11 @@ nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head)
|
|||
nv50_disp_super_ied_off(head, ior, 2);
|
||||
|
||||
/* If we're shutting down the OR's only active head, execute
|
||||
* the output path's release function.
|
||||
* the output path's disable function.
|
||||
*/
|
||||
if (ior->arm.head == (1 << head->id)) {
|
||||
if ((outp = ior->arm.outp) && outp->func->release)
|
||||
outp->func->release(outp, ior);
|
||||
if ((outp = ior->arm.outp) && outp->func->disable)
|
||||
outp->func->disable(outp, ior);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ nvkm_outp_release(struct nvkm_outp *outp, u8 user)
|
|||
if (ior) {
|
||||
outp->acquired &= ~user;
|
||||
if (!outp->acquired) {
|
||||
if (outp->func->release && outp->ior)
|
||||
outp->func->release(outp);
|
||||
outp->ior->asy.outp = NULL;
|
||||
outp->ior = NULL;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,8 @@ struct nvkm_outp_func {
|
|||
void (*init)(struct nvkm_outp *);
|
||||
void (*fini)(struct nvkm_outp *);
|
||||
int (*acquire)(struct nvkm_outp *);
|
||||
void (*release)(struct nvkm_outp *, struct nvkm_ior *);
|
||||
void (*release)(struct nvkm_outp *);
|
||||
void (*disable)(struct nvkm_outp *, struct nvkm_ior *);
|
||||
};
|
||||
|
||||
#define OUTP_MSG(o,l,f,a...) do { \
|
||||
|
|
Loading…
Reference in New Issue