drm/nouveau/disp: fix DP disable race
[ Upstream commit e04cfdc9b7398c60dbc70212415ea63b6c6a93ae ] 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>
This commit is contained in:
parent
1a255bf1e7
commit
112d65a51f
@ -412,14 +412,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;
|
||||
@ -428,6 +424,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)
|
||||
{
|
||||
@ -576,6 +582,7 @@ nvkm_dp_func = {
|
||||
.fini = nvkm_dp_fini,
|
||||
.acquire = nvkm_dp_acquire,
|
||||
.release = nvkm_dp_release,
|
||||
.disable = nvkm_dp_disable,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -436,11 +436,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;
|
||||
}
|
||||
|
@ -41,7 +41,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…
x
Reference in New Issue
Block a user