From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=51.250.60.162 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1792769078; b=pCQAejv7SFAuVu/Nn+OC3r66fAubeScGg5q5Rw7WoZlmbkzwdt8D93sTEIK333M2058h OaWU44JNmpFA5R8n0qtxSO2z7mYN0j4P02LZKl5EEnFx3fyK6yKEd07NbD02t9rhMVcaZ XPbfNuq6uoeCAArMbXstTeF0P4XFMJsBjWIyMCLXMXyoco/NwGKrNqJirQ1GDwR64Vdb8 w2yqAhJ22s151EpoQwxVl5HZ+1f+CrVUoN33dknZnlV95go2/4Pas/Ofqo/brVjQFVso0 1lhihjZQhz6/A4y325Wdm921LqvbXCJeJ96awrWnki6R7SCODRby/LCF92swhbQPcBQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792769078; h=DMARC-Filter:Received:Received:X-Yandex-Fwd:DKIM-Signature:From:To: Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=LbacRowWzwVnlWbExXUMiESmxUlI+FAcFK05tc4OaJ0=; b=sYhcMhEtY0l2TJkQihQRQ91fdbAbofvKDy7x3fGZfxqAkQw8fkEL7y2A3fYye2MnYpeN cGmJZ7zVofyYnokKrBO6iDEDeiGWnl3FXF1iecCp8UmUqyCLdcX7YN6XEDFGNB+H3ePhk ZtDRVF6JYLO0eECaAv6a432jh1L9P5OgwOXtPHStunweAIlVrUVSE1qsxXeju96C1L/Nn Zk9IvoLqs9clqwG54qTUfXKo7WH9vM8nzvvHP+9J+0WDT1mWhMBnqJlrU512rH9A3OODM vxgfbwZmWpi4jLVfrI2a8NqtP9pP96SY3fd/+Ch9oe9trpvUZ8vP7S1VeQF+JEWh/kw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=yandex.com; spf=pass smtp.mailfrom=yandex.com; dkim=pass header.d=yandex.com header.i=@yandex.com header.a=rsa-sha256 header.s=mail header.b=IngimSJw; arc=none smtp.remote-ip=51.250.60.162 Received: from forward102d.mail.yandex.net (forward102d.mail.yandex.net [51.250.60.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BAB22606A327 for ; Fri, 23 Oct 2026 15:24:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org BAB22606A327 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=yandex.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=yandex.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=yandex.com header.i=@yandex.com header.a=rsa-sha256 header.s=mail header.b=IngimSJw Received: from mail-nwsmtp-smtp-production-main-12.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-12.yp-c.yandex.net) by forward102d.mail.yandex.net (postfix) with ESMTPS id 28A12C017E; Fri, 23 Oct 2026 18:24:28 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-12 with ESMTPSA id GOf0WQDdMGk0-4OD3IW0V; Fri, 23 Oct 2026 18:24:27 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.com; s=mail; t=1792769067; bh=LbacRowWzwVnlWbExXUMiESmxUlI+FAcFK05tc4OaJ0=; h=Message-ID:Date:In-Reply-To:Cc:Subject:References:To:From; b=IngimSJw6n+DSn0/XNAB70exzvTkwmDZrUAthuRcBs2fspHRAX02TMVxXsjm/111U gP+AsKpm4qtjC8XTSFHs4qiroQnQT1oMDgvxMi5ueMjB4wmSzkSZpLBlEb5EUUyfXm 2oLBGTy5Lx8lAu3j8VpBsvYksZ5vlnbPJxDojeUw= Authentication-Results: mail-nwsmtp-smtp-production-main-12; dkim=pass header.i=@yandex.com From: Alex To: Lyude Paul , Danilo Krummrich Cc: Karol Herbst , nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, xnderv@yandex.com Subject: [PATCH v2] drm/nouveau: idle the channel before destroying an engine object via abi16 Date: Fri, 23 Oct 2026 18:23:32 +0300 Message-ID: <20261023152332.9420-2-xnderv@yandex.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261023152332.9420-1-xnderv@yandex.com> References: <20261023144219.46478-1-xnderv@yandex.com> <20261023152332.9420-1-xnderv@yandex.com> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Cc: dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org nouveau_abi16_ioctl_del() destroys an engine object (ENGOBJ) created by nouveau_abi16_ioctl_new() without waiting for the owning channel to go idle. The legacy path, nouveau_abi16_ioctl_gpuobj_free(), does call nouveau_channel_idle() first ("synchronize with the user channel and destroy the gpu object"), the new ioctl does not. Chromium-based applications (Chrome, Yandex Browser, Electron apps) create and immediately delete probe 3D objects at startup. If the GPU is busy with other work at that moment (compositor animation while the app is launched from the GNOME dash, cursor movement), the engine context is unbound while the channel still references it, and the GPU faults: nouveau 0000:01:00.0: fifo: fault 00 [VIRT_READ] at 0000000000000000 engine 00 [GR] client 0f [HUB/CTXCTL] reason 00 [PDE] on channel 5 nouveau 0000:01:00.0: fifo: ... PAGE_NOT_PRESENT ... channel 5 killed! after which the desktop freezes. Observed on GF114 (GeForce GTX 560 Ti) with Linux 7.0.x, reproducible almost every time by launching a Chromium app from the dash; not seen in 10 consecutive launches with this patch. Remember the channel an engine object was created on, drop the reference when the channel is destroyed first, and idle the channel before nvif_object_dtor() like the gpuobj_free path does. Signed-off-by: Alex --- v2: wait for the channel's scheduler to drain before idling the channel when VM_BIND is in use. Legacy PUSHBUF submissions are serialized with the ioctl by cli->mutex, but EXEC jobs are pushed to the channel asynchronously from the scheduler workqueue, so emitting a fence from nouveau_abi16_ioctl_del() could race with nouveau_exec_job_run(), and jobs still queued in the entity would not have been covered by the fence at all. Reuse the existing job-list wait from nouveau_sched_fini() through a small helper, nouveau_sched_wait_idle(). (Race pointed out by the Sashiko AI review of v1.) drivers/gpu/drm/nouveau/nouveau_abi16.c | 27 +++++++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_sched.c | 9 +++++++- drivers/gpu/drm/nouveau/nouveau_sched.h | 1 + 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index b776030..d979cd8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -89,6 +89,7 @@ struct nouveau_abi16_obj { ENGOBJ, } type; u64 object; + struct nouveau_abi16_chan *chan; struct nvif_object engobj; @@ -173,6 +174,13 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, struct nouveau_abi16_chan *chan) { struct nouveau_abi16_ntfy *ntfy, *temp; + struct nouveau_abi16_obj *obj; + + /* Forget references to this channel held by engine objects. */ + list_for_each_entry(obj, &abi16->objects, head) { + if (obj->chan == chan) + obj->chan = NULL; + } /* Cancel all jobs from the entity's queue. */ if (chan->sched) @@ -784,8 +792,24 @@ nouveau_abi16_ioctl_del(struct nouveau_abi16 *abi16, struct nvif_ioctl_v0 *ioctl obj = nouveau_abi16_obj_find(abi16, ioctl->object); if (obj) { - if (obj->type == ENGOBJ) + if (obj->type == ENGOBJ) { + /* Synchronize with the user channel before destroying the + * engine object, as the legacy GPUOBJ_FREE path does. The + * channel may still have work queued that needs the engine + * context which is about to be unbound. + * + * Legacy PUSHBUF submissions are serialized with this ioctl + * by cli->mutex. With VM_BIND, EXEC jobs are pushed to the + * channel asynchronously by the scheduler, so wait for every + * submitted job to finish before touching the channel. + */ + if (obj->chan && obj->chan->chan) { + if (obj->chan->sched) + nouveau_sched_wait_idle(obj->chan->sched); + nouveau_channel_idle(obj->chan->chan); + } nvif_object_dtor(&obj->engobj); + } nouveau_abi16_obj_del(obj); } @@ -826,6 +850,7 @@ nouveau_abi16_ioctl_new(struct nouveau_abi16 *abi16, struct nvif_ioctl_v0 *ioctl obj = nouveau_abi16_obj_new(abi16, ENGOBJ, args->object); if (IS_ERR(obj)) return PTR_ERR(obj); + obj->chan = chan; ret = nvif_object_ctor(&chan->chan->user, "abi16EngObj", args->handle, args->oclass, NULL, 0, &obj->engobj); diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index b3f02c4..956ca73 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -493,13 +493,20 @@ nouveau_sched_job_list_empty(struct nouveau_sched *sched) return empty; } +/* Wait until every job submitted to the scheduler has finished. */ +void +nouveau_sched_wait_idle(struct nouveau_sched *sched) +{ + wait_event(sched->job.wq, nouveau_sched_job_list_empty(sched)); +} + static void nouveau_sched_fini(struct nouveau_sched *sched) { struct drm_gpu_scheduler *drm_sched = &sched->base; struct drm_sched_entity *entity = &sched->entity; - wait_event(sched->job.wq, nouveau_sched_job_list_empty(sched)); + nouveau_sched_wait_idle(sched); drm_sched_entity_fini(entity); drm_sched_fini(drm_sched); diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h index 51ce8dc..0562af6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.h +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -115,5 +115,6 @@ struct nouveau_sched { int nouveau_sched_create(struct nouveau_sched **psched, struct nouveau_drm *drm, struct workqueue_struct *wq, u32 credit_limit); void nouveau_sched_destroy(struct nouveau_sched **psched); +void nouveau_sched_wait_idle(struct nouveau_sched *sched); #endif