From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB346442B08 for ; Tue, 4 Aug 2026 10:10:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838204; cv=none; b=tlBQad/m0RYgZR06keYEoriplSNyDzvgrrLtY4vyrKX3vzuNdqEVVNTHF8XoYZBpmrCx14BEMOxRwgKQunNpgwmvat+Q163l/H1oByzIRJNtO33XpvjDHTxtmNJP1ektp0bciX4tvP5c2A73ozdz3KkLXLk4Nbee2VxzY2497Wk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838204; c=relaxed/simple; bh=4PEo6ltYK2sqYwCSiPvreVKFxzAiD3FX1R2hrd+AH3U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=aTn8HXgLSgS7THskQ6hOCOZXldftvJhajwF1YkTWmsIwH3w/gPRj0JR7u1hqt0YsknD62xNjg73+U0N8ySGn64B5QT2kNublQnIf/jpq8B4Y95+5Xmn0BO5mRve/ktqv5bgB7YQ3Xa/vKAjlOwh7OzEWBBWORyM8IgbLyg0W7EI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=LI6crjvx; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="LI6crjvx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838195; bh=4PEo6ltYK2sqYwCSiPvreVKFxzAiD3FX1R2hrd+AH3U=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=LI6crjvxTIltXjO90Pi3swewEMUtJJDKDw3R8nLTyiv8QKuJEsGxAtjNXf7W0Ng/b eVoqQKyA/9mmeC6YmyNcmS/6K3q1eckeWg+Qg6sZ/Hup8/7dlxmqw+jL9tD/KphWjO 9zZkL7uFUuAGyfEZuBM3BspDpL8kAgmZwkRRbiBlzVKchPclkBQN2FLulawJEP1fTq XMPD7tbYwcuNZ35KC4PG4gfkElPmxojvBXPrdxz4xbDBfGpQW8pvDwwsjvAe97qObG WHwZfUmLR83luC9l26xW7Z09wujM9d5kZ6ngXi977bqETCR0pU4NkSTfyupFSjSphL HWp+Wdy+MPIbQ== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id EA9EF17E0896; Tue, 04 Aug 2026 12:09:54 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:40 +0200 Subject: [PATCH 01/12] drm/panthor: Disable reset work before unplug Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-1-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=848; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=4PEo6ltYK2sqYwCSiPvreVKFxzAiD3FX1R2hrd+AH3U=; b=8nNhBu4EHMzZ3AIzEC7YY7+Renks/fLDZZHuV5IlF3GxaRIRd4+Rs9owJzfBztP6OsgygCZcd IqjEJSwOLaFBKx1bP5/qno68gaT8MggcBBVFTRqcxbhS3LZKkx4bYkE X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= Make sure we're not interrupted by resets while we're unplugging. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index 0b25abebb803..e7f5744bc1e3 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -86,6 +86,9 @@ void panthor_device_unplug(struct panthor_device *ptdev) */ drm_dev_unplug(&ptdev->base); =20 + /* Make sure we're not interrupted by resets while we're unplugging. */ + disable_work_sync(&ptdev->reset.work); + /* We do the rest of the unplug with the unplug lock released, * future callers will wait on ptdev->unplug.done anyway. */ --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D85A23EEAE9 for ; Tue, 4 Aug 2026 10:10:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838205; cv=none; b=qUh6ySMUHlE8OCTqlxmo7HJa95vlglmRMFTLmXLydjC4YvD0qKvICi7HoXzgeVZZqakErbnGS4i7HzeKeLW1/NwJt89eSP9wgKGcHMEa7xcMfhXwI1hESfTwdy1LJIUjYdOyxt3LZEwbIuW9ISGfpXBvPwa9dXUPsFY9hUKPn/0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838205; c=relaxed/simple; bh=bw8BRqvrbmjm2Ay6J4F1Fc0dW2CKmWRpBs5XRbS00t8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nZF2N9Aq0/tL6GqeuR1OYmn0nk38yzY10aLIiMxQ5TqD0NS01sDhOKClKSS67Yg7soHmGTYosSEic0Af7vZK8rp2ap0NnJtPUExrFap4gd4DwDPaoI7b9gIJkoEj2SCCHs6x3tD4AihMPzDnwM8+t/vLMpzckyFRsyYOB1rlxuA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=jBeIo4MS; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="jBeIo4MS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838195; bh=bw8BRqvrbmjm2Ay6J4F1Fc0dW2CKmWRpBs5XRbS00t8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=jBeIo4MSY3clcXip4Bd9qsbehpIkIUkbhWBStAaEz3sPxjcSj1OlhqRYqzRzvW6ib 6z8TJC5XXBRQxdv2kJBQ1XnCdgZSjISuJom4lXOTcuGwK+p9i7TidF2BLevzrmu2dO 60QwSJ+45wVLiCcKZLTSxTKAd5TWV4vf77kVQ+VBFbSqAQFr+DszyicSh1W0s6t/MV UdZQn0SI3rWi8K5GZq8xPkPXdvgFTHCGWSBzsbRRIo/rAgAsUBtwP0Hg1yZTKBwWQw oPx6QHYI4JxC/HAVVVD85KZq02Iw1Qc4vj+IvHDl/er89a1T6IqOuw0CIp2xpHmcRq NOZa//4gArKuA== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 72BF217E08F0; Tue, 04 Aug 2026 12:09:55 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:41 +0200 Subject: [PATCH 02/12] drm/panthor: Further delay reset work enablement Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-2-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=1523; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=bw8BRqvrbmjm2Ay6J4F1Fc0dW2CKmWRpBs5XRbS00t8=; b=jDRrvR9u2E3k4UcOAUI6nDgdY1gOwLvjeWack6yZDh5a+787VadxFqGDlGj7z1CVBJKrp7JG/ h/rIhIYnfU7A366ca4TasEqiKxE9x8Uw0MlOXuwG5MRYnpvNnrwnhbK X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= There's no point re-enabling the reset work before the DRM device registration succeeds, so move the enable_work() after the point where nothing can fail anymore, and in the unlikely event where a reset was pending, reschedule it. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index e7f5744bc1e3..1aa86d00646f 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -289,9 +289,6 @@ int panthor_device_init(struct panthor_device *ptdev) =20 panthor_gem_init(ptdev); =20 - /* Now that everything is initialized, we can enable the reset work. */ - enable_work(&ptdev->reset.work); - /* ~3 frames */ pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50); pm_runtime_use_autosuspend(ptdev->base.dev); @@ -300,6 +297,14 @@ int panthor_device_init(struct panthor_device *ptdev) if (ret) goto err_disable_autosuspend; =20 + /* Now that everything is initialized, we can enable the reset work. + * If there was a reset pending, clear and reschedule, otherwise the + * reset.pending bit is stuck. + */ + enable_work(&ptdev->reset.work); + if (atomic_cmpxchg(&ptdev->reset.pending, 1, 0)) + panthor_device_schedule_reset(ptdev); + pm_runtime_put_autosuspend(ptdev->base.dev); return 0; =20 --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D86E24446F9 for ; Tue, 4 Aug 2026 10:10:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838205; cv=none; b=B8O4rzokKbDTAQWd8inVElNUl50PKopRY4rgr47dAWvsNrvnX5pqn8pM5n0JK5UatATJoXRqDkBeGY3aRtadQ5M2lm199xG3wYl55HeZGbNdrWYvqp/Gtrj9PHWKJPo4mBLLwbjI/lKysJoOBT+M5JHx0gL8+EyKE8ZLtjciqEc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838205; c=relaxed/simple; bh=YqEY51AaClJsLFVXwpEXOrnUItYnhK9wUpsMaXBZvdQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=h0BxRsCw3fN26Gtuc0UVDXxOQNOJWxpGnnSjVHz2VneUWUIfj+/1UQ1HrT+VVHUGNvvr4jAPBQIVetV/9QRtuoP+zh1ozcpc+5xMKElfEuVYCzS7VZHWS30UX5kWSSQYGV+cBVElVvW2mTQTH+CRitZhwwn0UIQj5s42eX7YoU4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=JehKUtJI; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="JehKUtJI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838196; bh=YqEY51AaClJsLFVXwpEXOrnUItYnhK9wUpsMaXBZvdQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=JehKUtJIn46HZsbsnSzOrv+IYdVv4lkPswPEWx+LiRHJhlzn9veHDDOnmMSHg7caE F4jOkOP3k+irrUXj7Fnnjq/fGVb3cHQGjrIkKrJ8MAEKHbC7wGOLCORm4y/S8TNx0F klBcj/8Zn3oUI6BXP8sPshDKVznkL58NvHThsKZe/dB/GU6x7Ej8tcFPtn3U7q6/Lh 9ljWSIwnSa3vmo8v0WVLXhY/TuaAuXomSso8pfZFGH91zigqCbzdOC4daoNZjX4Mp1 YdPRLpupKpCV5DF0m5K7X+AUeGC/V0uJKMH5HZhWBvAdUI5bOb/SejdUB7Mc07E7XG Mc6j7qFIKdkbw== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id F1D8017E0FEA; Tue, 04 Aug 2026 12:09:55 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:42 +0200 Subject: [PATCH 03/12] drm/panthor: Move the debugfs initialization to panthor_device.c Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-3-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=2729; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=YqEY51AaClJsLFVXwpEXOrnUItYnhK9wUpsMaXBZvdQ=; b=U3EzBc/BQN0Bv89K/9d/DmfbJwt2M85uvQHrzSb8V5OEf6wn8YE0BdBc1npdhOmWMH2PhELGX e2ztH04jcN8DBjd8TmnuTXyuIrZgwJ7kNXIfcqQ/zpkqOWZGyq1otfE X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= Those are per-device debugfs-files, so it makes sense to have the initialization logic in panthor_device.c. Signed-off-by: Boris Brezillon Reviewed-by: Liviu Dudau --- drivers/gpu/drm/panthor/panthor_device.c | 9 +++++++++ drivers/gpu/drm/panthor/panthor_device.h | 4 ++++ drivers/gpu/drm/panthor/panthor_drv.c | 10 +--------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index 1aa86d00646f..7d336f160d1f 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -13,6 +13,7 @@ #include =20 #include +#include #include #include =20 @@ -616,3 +617,11 @@ int panthor_device_suspend(struct device *dev) atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDED); return 0; } + +#ifdef CONFIG_DEBUG_FS +void panthor_device_debugfs_init(struct drm_minor *minor) +{ + panthor_mmu_debugfs_init(minor); + panthor_gem_debugfs_init(minor); +} +#endif diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/pan= thor/panthor_device.h index 0fda64fbe5f2..a6b1a2a5fca4 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -403,6 +403,10 @@ int panthor_device_mmap_io(struct panthor_device *ptde= v, int panthor_device_resume(struct device *dev); int panthor_device_suspend(struct device *dev); =20 +#ifdef CONFIG_DEBUG_FS +void panthor_device_debugfs_init(struct drm_minor *minor); +#endif + static inline int panthor_device_resume_and_get(struct panthor_device *ptd= ev) { int ret =3D pm_runtime_resume_and_get(ptdev->base.dev); diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/pantho= r/panthor_drv.c index 46a3080b0b20..924a7ecd3733 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1764,14 +1764,6 @@ static const struct file_operations panthor_drm_driv= er_fops =3D { .fop_flags =3D FOP_UNSIGNED_OFFSET, }; =20 -#ifdef CONFIG_DEBUG_FS -static void panthor_debugfs_init(struct drm_minor *minor) -{ - panthor_mmu_debugfs_init(minor); - panthor_gem_debugfs_init(minor); -} -#endif - /* * PanCSF driver version: * - 1.0 - initial interface @@ -1807,7 +1799,7 @@ static const struct drm_driver panthor_drm_driver =3D= { .gem_prime_import_sg_table =3D panthor_gem_prime_import_sg_table, .gem_prime_import =3D panthor_gem_prime_import, #ifdef CONFIG_DEBUG_FS - .debugfs_init =3D panthor_debugfs_init, + .debugfs_init =3D panthor_device_debugfs_init, #endif }; =20 --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B8FFD4477FB for ; Tue, 4 Aug 2026 10:10:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838206; cv=none; b=bY+GG9SaGlJe6NNe7ILF+bgvEKTfhmVflde6+nmPU2taugEeNYDf90/guUs3LkCDwoz+SMrlTx2Rf1H0uh1pzUp1TaF1XAbiL96/drTFMBptnvekQzmPxQkwNyB5lAUgunVAp3y1XPQMbZl3EeQQGgvTdfvMTiN1MjO/klo4xYI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838206; c=relaxed/simple; bh=BJ44gq7DJG+fqcEq/10trwLCTnEL2m5O1yzLhaGrkSE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QAkoV3ITB8D7roUdSWH+OcgryYrrAO2BK+hsKSbsfuFfFRIwQj2Df5epQJQ7V+2aX/Af54hsU5pGFcf9y+Qi7vG13i7vgLHncJDtNB2uE0QfGPF41QeX+xMm+tNnz7SwRmAQ843MzAOuhdqBM2fTyHJORvZOxX9zzOvz8P4t4ks= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=bviWPcyC; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="bviWPcyC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838196; bh=BJ44gq7DJG+fqcEq/10trwLCTnEL2m5O1yzLhaGrkSE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=bviWPcyC99z+IA7wiTxcqOblH4VmwfjWMVB/6d+IqG758ZeXbsq4F+lBszHtgoMee TqST+krLCRNwOB36sxzzrvkkONLtuIEgAO7NnB4+t3jEeyYUNahs+E5MHv8819ny6S /8PrqcqWhojms9q22T7Q/QfZmGQmU8wirV2ezlc+Vv5hDYJIZB/XKLsZcBvbBU80Tb AeKYvgKlqTHmt1SInvFakmg+tTENwX4P97Vs4hW+z/N/RpnorT88yjAd3GC0fRlhL/ wA3mpMPqK5lIU+gmoH92HHlKNKR5z5M3wtGeizlw8ObhOxsS+aTVZfNGJzc1O6G55m fQJuiF3ODaD9g== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 7B5F917E107E; Tue, 04 Aug 2026 12:09:56 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:43 +0200 Subject: [PATCH 04/12] drm/panthor: Flush the cleanup_wq before destroying the drm_device Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-4-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon , sashiko-bot@kernel.org X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=1855; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=BJ44gq7DJG+fqcEq/10trwLCTnEL2m5O1yzLhaGrkSE=; b=COigHaAxvmSpC/bnWfhRWPhMjmV8cY9tQQbf2Evb/cDbimlOUB/2t6fGGjs4zjYwv2wM2GASN KREVcpnLZIMCu9U0quMWjC+Zelc4949EUEcivColYwysru9y9qIuOaw X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= If we don't do that, we might face various UAFs, because the resource referenced by these work items might be gone. In order to flush the panthor_cleanup_wq before device destruction, we simply register a drmm action. This action is intentionally inserted before any of the subcomponent _init() function to make sure we flush any cleanup work that might have been queued in there if the initialization fails. Fixes: de8548813824 ("drm/panthor: Add the scheduler logical block") Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block") Reported-by: sashiko-bot@kernel.org Closes: https://sashiko.dev/#/patchset/20260625-panthor-signal-from-irq-v5-= 0-8836a74e0ef9@collabora.com?part=3D2 Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index 7d336f160d1f..b7c55a6f4f08 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -167,6 +167,14 @@ static void panthor_device_free_page(struct drm_device= *ddev, void *data) __free_page(data); } =20 +static void panthor_device_flush_cleanup_wq(struct drm_device *ddev, void = *data) +{ + /* Make sure works queued to panthor_cleanup_wq are executed + * before the device is destroyed. + */ + flush_workqueue(panthor_cleanup_wq); +} + int panthor_device_init(struct panthor_device *ptdev) { u32 *dummy_page_virt; @@ -220,6 +228,10 @@ int panthor_device_init(struct panthor_device *ptdev) if (ret) return ret; =20 + ret =3D drmm_add_action(&ptdev->base, panthor_device_flush_cleanup_wq, NU= LL); + if (ret) + return ret; + ret =3D panthor_clk_init(ptdev); if (ret) return ret; --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81A314562A4 for ; Tue, 4 Aug 2026 10:10:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838208; cv=none; b=cSHGRbri9e0nAxfElEtQoXPlZTlbwFr5ZxJZYnWOQOSCznBYTpYOYwdn1LYOFVe65INvu8vy4yG36t1EzMZYnJ98wXKbDp6RHG/0SBAtJAhwW4c2QNhsQ0070B3THbkuLRNnHzn6LYwJ+uTnBzjxB4myRP/r7EkyZKhwGeHYIP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838208; c=relaxed/simple; bh=XSkdnZ3DAajEze2bLqfJRokm+VnLLdWLRJ+UFTlbJQc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UfhOUv4Joz3LS8/Q/Nr8tY4pTTcBksz1tB0ubx+0+XansFs2TZL6A+WwUq3vbHQvrLAs4uwrjqLJUNb2z0fgblXlBCJGg3tcfzujZHxQTDyh4NW4b07sONDBHLaJnNxqYqiRnzwNsWjDKcpAgdUjkfKzIbVEkR0V6OOjpKI0GNk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=SWl9AtfL; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="SWl9AtfL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838197; bh=XSkdnZ3DAajEze2bLqfJRokm+VnLLdWLRJ+UFTlbJQc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=SWl9AtfL9RJXNaTOSzp0kSfbd1/iSCDFvD4SO/L0e6SdfSTqZw+lr3sBPeGK56AJ6 vV/fNRGqpjZdp/4+TSuBNI/HMHPiOnPybISC+Y5NdWF4JXvOu4cmXtjL+Y9kpVZNDc W1qPSvuu8/vr/apOJPBdsw+rW/vlLySPaLgIjMupG+D9ejCa5UIK2c8x5UfGwNgyVc uoQAki01Fl7pAZP8zySc5GLJXHKPWqGRkJOG00F6WVROfMhW6EF4AvQyiquRDDTCGg O92HZ2ZxBuFQK4VTs6M5PxIyfvTeA8O83LXjeejXK62K8RNbIMeECWILJ6GrMt2LtZ myR9cKTgaOUdQ== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 0E70117E10B0; Tue, 04 Aug 2026 12:09:57 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:44 +0200 Subject: [PATCH 05/12] drm/panthor: Drop unused vm argument passed to panthor_vm_prepare_sync_only_op_ctx() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-5-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=1147; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=XSkdnZ3DAajEze2bLqfJRokm+VnLLdWLRJ+UFTlbJQc=; b=MyQVSW28q59iRpuCNhgnEsXtCbVbJn9xTxh/XLYf9IvK9HLWs2UrxIOXLkMp0Jmhg765LTVEM lZQMnqrlwRMBj4iaYQEUqLxmZrEhfmgtVNLkePN8NOphBmUybf/izE5 X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= No need to pass a panthor_vm around if it's unused. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index 0182b72f1932..fb9dec64d320 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1463,8 +1463,8 @@ static int panthor_vm_prepare_unmap_op_ctx(struct pan= thor_vm_op_ctx *op_ctx, return ret; } =20 -static void panthor_vm_prepare_sync_only_op_ctx(struct panthor_vm_op_ctx *= op_ctx, - struct panthor_vm *vm) +static void +panthor_vm_prepare_sync_only_op_ctx(struct panthor_vm_op_ctx *op_ctx) { memset(op_ctx, 0, sizeof(*op_ctx)); op_ctx->flags =3D DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY; @@ -3026,7 +3026,7 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file, if (!op->syncs.count) return -EINVAL; =20 - panthor_vm_prepare_sync_only_op_ctx(op_ctx, vm); + panthor_vm_prepare_sync_only_op_ctx(op_ctx); return 0; =20 default: --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 817F24446EC for ; Tue, 4 Aug 2026 10:10:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838212; cv=none; b=Z+m8YaiAsw6DX6Mwxr1wQeSq15SUxxaWhltUwuh7q65/WQ2k+uXhaeGHaM+9hIky2GHUhFj3gMlICUSQVT0QD2MGn2VsySL09PRFAvozKHuE+K/Qpaomkp0MdLWM2GobLrJLFirkz6p+dJhtfwsx+WgnuuQ4V64cfA27vzNI61o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838212; c=relaxed/simple; bh=f8vFWPW3Sz1raEvU2KHEctAC8v0qwf+N55cUGo+b5zE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GZptqOkOxkyFvS7oJF6e+xxuYZoOzIJrh7wRCO8szHuU7L6RaZzxP5NQemtdix047KyfhRotk3UNZ8yfbBClQ6hDm6rCt8Ab01u56ExlSZC0sIq4twDlXk7IgSTqXLpAz74F/unx9zezoI7zTZ+EWwBayYuspr1lcI9CRXjCgYE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=eXxJQ1AB; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="eXxJQ1AB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838198; bh=f8vFWPW3Sz1raEvU2KHEctAC8v0qwf+N55cUGo+b5zE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=eXxJQ1ABPN5qlvU9yUIlnkrbHTeyXlR6MkktcvpoytPNAChTaglmkl4D85lR1B9g3 lPPrUTAEtGrYr7ss7d5HVSGn0uflbpI65c2EOs44Iblr06siRFVtvjqufSfGw5ETID ZkKiy+JfPctyskvaJoFFjQ6UZ+TFu4YW3fH3NwUunRtxouWbxs2KesHzi8T9l+OOe2 6coR+cEzf7Z0shCltJx3FkE069VBLubdnFiezhD0P6QiDuCdilahYbrDyVEi08Zzn5 d5YbcDjnhg8y9LQdNU16uONc6DdjDnxTDcXAhGq3FdH/TGwt44cqlIELvWbcY6h6lO 3KBQqI7b5jGog== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 8BF0F17E10BC; Tue, 04 Aug 2026 12:09:57 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:45 +0200 Subject: [PATCH 06/12] drm/panthor: Split panthor_vm Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-6-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=79357; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=f8vFWPW3Sz1raEvU2KHEctAC8v0qwf+N55cUGo+b5zE=; b=dsaT4JGE+/KzJeL7Svn7vNK6JtKpEFa/D/SoDe6NVUS2nXJpDVs21re5VI1l8y0RJeqPYlZMn UmdXXaQGR/oCJj/jBWBOoxb/WA89FMp1S8yv3y451y+PL8W00+owVS5 X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= The way things are currently defined makes the cleanup procedure harder because the panthor_vm object cleanup happens after drm_gpuvm_fini() has been called, and sometimes we need a drm_gpuvm to undo things. This has been worked around by things like the panthor_vm_unmap_range() call in panthor_vm_destroy(), but there are still situations where this is problematic, like the show_each_vm() where we walk a list of VM and call drm_debugfs_gpuva_info() on each, with the risk of hitting an object that had drm_gpuvm_fini() called on it already. There's more of these tricky situations to come when we get to making the unplug logic more robust, so let's address the problem ahead of it and split the panthor_vm object in two: - panthor_as: this is the object embedding drm_gpuvm and more generally dealing with page table updates/residency - panthor_vm: this is the user-visible object wrapping around panthor_as. Among other things, it contains the scheduler for the bind queue and the drm_mm tree for kernel BO allocation. This object owns a drm_gpuvm ref. With this in place, we can do the cleanup steps that need a valid drm_gpuvm object in panthor_vm_release(), and the rest is cleaned up in panthor_vm_pgtable_free(). Note that there's a bunch of s/as[_nr]/slot/ variable/argument renames to clear the confusion between the AS slot number and the newly introduced panthor_as object. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 1052 +++++++++++++++++------------= ---- 1 file changed, 552 insertions(+), 500 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index fb9dec64d320..2d462813a711 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -41,14 +41,14 @@ =20 #define MAX_AS_SLOTS 32 =20 -struct panthor_vm; +struct panthor_as; =20 /** * struct panthor_as_slot - Address space slot */ struct panthor_as_slot { - /** @vm: VM bound to this slot. NULL is no VM is bound. */ - struct panthor_vm *vm; + /** @as: AS bound to this slot. NULL if no AS is bound. */ + struct panthor_as *as; }; =20 /** @@ -77,19 +77,19 @@ struct panthor_mmu { /** @as.faulty_mask: Bitmask encoding the faulty slots. */ unsigned long faulty_mask; =20 - /** @as.slots: VMs currently bound to the AS slots. */ + /** @as.slots: AS currently bound to the AS slots. */ struct panthor_as_slot slots[MAX_AS_SLOTS]; =20 /** - * @as.lru_list: List of least recently used VMs. + * @as.lru_list: List of least recently used AS. * - * We use this list to pick a VM to evict when all slots are + * We use this list to pick an AS to evict when all slots are * used. * - * There should be no more active VMs than there are AS slots, - * so this LRU is just here to keep VMs bound until there's - * a need to release a slot, thus avoid unnecessary TLB/cache - * flushes. + * There should be no more active AS than there are AS slots, + * so this LRU is just here to keep page tables bound until + * there's a need to release a slot, thus avoiding unnecessary + * TLB/cache flushes. */ struct list_head lru_list; } as; @@ -153,9 +153,9 @@ struct panthor_vma { }; =20 /** - * struct panthor_vm_op_ctx - VM operation context + * struct panthor_as_op_ctx - AS operation context * - * With VM operations potentially taking place in a dma-signaling path, we + * With AS operations potentially taking place in a dma-signaling path, we * need to make sure everything that might require resource allocation is * pre-allocated upfront. This is what this operation context is far. * @@ -163,7 +163,7 @@ struct panthor_vma { * asynchronously, and let the VM_BIND scheduler process the next VM_BIND * request. */ -struct panthor_vm_op_ctx { +struct panthor_as_op_ctx { /** @rsvd_page_tables: Pages reserved for the MMU page table update. */ struct { /** @rsvd_page_tables.count: Number of pages reserved. */ @@ -215,13 +215,120 @@ struct panthor_vm_op_ctx { } map; }; =20 +/** + * struct panthor_as - Used to managed a GPU address space. + */ +struct panthor_as { + /** + * @base: Inherit from drm_gpuvm. + * + * We delegate all the VA management to the common drm_gpuvm framework + * and only implement hooks to update the MMU page table. + */ + struct drm_gpuvm base; + + /** @memattr: Value to program to the AS_MEMATTR register. */ + u64 memattr; + + /** @pt: Page table fields. */ + struct { + /** @pt.ops: Page table ops. */ + struct io_pgtable_ops *ops; + + /** @pt.root: Page table root. */ + void *root; + } pt; + + /** + * @op_lock: Lock used to serialize operations on the AS. + * + * The serialization of jobs queued to the VM_BIND queue is already + * taken care of by drm_sched, but we need to serialize synchronous + * and asynchronous VM_BIND request. This is what this lock is for. + */ + struct mutex op_lock; + + /** + * @op_ctx: The context attached to the currently executing operation. + * + * NULL when no operation is in progress. + */ + struct panthor_as_op_ctx *op_ctx; + + /** @active_cnt: Number of active users of this address space. */ + refcount_t active_cnt; + + /** @hw_slot: Hardware slot related fields. */ + struct { + /** + * @hw_slot.id: ID of the slot this AS is bound to. + * + * A value of -1 means the AS is inactive/not bound. + */ + int id; + + /** + * @hw_slot.lru_node: Used to insert the AS in panthor_mmu::as::lru_list. + * + * Active ASs should not be inserted in the LRU list. + */ + struct list_head lru_node; + } hw_slot; + + /** + * @unusable: True if the AS has turned unusable because something + * bad happened during an asynchronous request. + * + * We don't try to recover from such failures, because this implies + * informing userspace about the specific operation that failed, and + * hoping the userspace driver can replay things from there. This all + * sounds very complicated for little gain. + * + * Instead, we should just flag the AS as unusable, and fail any + * further request targeting this AS. + * + * We also provide a way to query an AS state, so userspace can + * destroy it and create a new one. + * + * As an analogy, this would be mapped to a VK_ERROR_DEVICE_LOST + * situation, where the logical device needs to be re-created. + */ + bool unusable; + + /** + * @unhandled_fault: Unhandled fault happened. + * + * This should be reported to the scheduler, and the queue/group be + * flagged as faulty as a result. + */ + bool unhandled_fault; + + /** @locked_region: Information about the currently locked region current= ly. */ + struct { + /** @locked_region.start: Start of the locked region. */ + u64 start; + + /** @locked_region.size: Size of the locked region. */ + u64 size; + } locked_region; + + /** @reclaim: Fields related to BO reclaim. */ + struct { + /** @reclaim.lru: LRU of BOs that are only mapped to this AS. */ + struct drm_gem_lru lru; + + /** + * @reclaim.lru_node: Node used to insert the AS in + * panthor_device::reclaim::vms. + */ + struct list_head lru_node; + } reclaim; +}; + /** * struct panthor_vm - VM object * * A VM is an object representing a GPU (or MCU) virtual address space. - * It embeds the MMU page table for this address space, a tree containing - * all the virtual mappings of GEM objects, and other things needed to man= age - * the VM. * * Except for the MCU VM, which is managed by the kernel, all other VMs are * created by userspace and mostly managed by userspace, using the @@ -233,13 +340,11 @@ struct panthor_vm_op_ctx { * by default). */ struct panthor_vm { - /** - * @base: Inherit from drm_gpuvm. - * - * We delegate all the VA management to the common drm_gpuvm framework - * and only implement hooks to update the MMU page table. - */ - struct drm_gpuvm base; + /** @refcount: VM refcount. */ + struct kref refcount; + + /** @as: VM address space. */ + struct panthor_as *as; =20 /** * @sched: Scheduler used for asynchronous VM_BIND request. @@ -256,34 +361,6 @@ struct panthor_vm { */ struct drm_sched_entity entity; =20 - /** @ptdev: Device. */ - struct panthor_device *ptdev; - - /** @memattr: Value to program to the AS_MEMATTR register. */ - u64 memattr; - - /** @pgtbl_ops: Page table operations. */ - struct io_pgtable_ops *pgtbl_ops; - - /** @root_page_table: Stores the root page table pointer. */ - void *root_page_table; - - /** - * @op_lock: Lock used to serialize operations on a VM. - * - * The serialization of jobs queued to the VM_BIND queue is already - * taken care of by drm_sched, but we need to serialize synchronous - * and asynchronous VM_BIND request. This is what this lock is for. - */ - struct mutex op_lock; - - /** - * @op_ctx: The context attached to the currently executing VM operation. - * - * NULL when no operation is in progress. - */ - struct panthor_vm_op_ctx *op_ctx; - /** * @mm: Memory management object representing the auto-VA/kernel-VA. * @@ -313,26 +390,6 @@ struct panthor_vm { /** @user_va_range: Upper boundary of VAs VM users can map objects agains= t. */ u64 user_va_range; =20 - /** @as: Address space related fields. */ - struct { - /** - * @as.id: ID of the address space this VM is bound to. - * - * A value of -1 means the VM is inactive/not bound. - */ - int id; - - /** @as.active_cnt: Number of active users of this VM. */ - refcount_t active_cnt; - - /** - * @as.lru_node: Used to instead the VM in the panthor_mmu::as::lru_list. - * - * Active VMs should not be inserted in the LRU list. - */ - struct list_head lru_node; - } as; - /** * @heaps: Tiler heap related fields. */ @@ -361,55 +418,6 @@ struct panthor_vm { */ bool destroyed; =20 - /** - * @unusable: True if the VM has turned unusable because something - * bad happened during an asynchronous request. - * - * We don't try to recover from such failures, because this implies - * informing userspace about the specific operation that failed, and - * hoping the userspace driver can replay things from there. This all - * sounds very complicated for little gain. - * - * Instead, we should just flag the VM as unusable, and fail any - * further request targeting this VM. - * - * We also provide a way to query a VM state, so userspace can destroy - * it and create a new one. - * - * As an analogy, this would be mapped to a VK_ERROR_DEVICE_LOST - * situation, where the logical device needs to be re-created. - */ - bool unusable; - - /** - * @unhandled_fault: Unhandled fault happened. - * - * This should be reported to the scheduler, and the queue/group be - * flagged as faulty as a result. - */ - bool unhandled_fault; - - /** @locked_region: Information about the currently locked region current= ly. */ - struct { - /** @locked_region.start: Start of the locked region. */ - u64 start; - - /** @locked_region.size: Size of the locked region. */ - u64 size; - } locked_region; - - /** @reclaim: Fields related to BO reclaim. */ - struct { - /** @reclaim.lru: LRU of BOs that are only mapped to this VM. */ - struct drm_gem_lru lru; - - /** - * @reclaim.lru_node: Node used to insert the VM in - * panthor_device::reclaim::vms. - */ - struct list_head lru_node; - } reclaim; - /** * @dummy: Dummy object used for sparse mappings. * @@ -437,7 +445,7 @@ struct panthor_vm_bind_job { struct panthor_vm *vm; =20 /** @ctx: Operation context. */ - struct panthor_vm_op_ctx ctx; + struct panthor_as_op_ctx ctx; }; =20 /* @@ -466,36 +474,37 @@ static struct kmem_cache *pt_cache; */ static void *alloc_pt(void *cookie, size_t size, gfp_t gfp) { - struct panthor_vm *vm =3D cookie; + struct panthor_as *as =3D cookie; + struct panthor_as_op_ctx *op_ctx =3D as->op_ctx; + struct drm_device *ddev =3D as->base.drm; void *page; =20 /* Allocation of the root page table happening during init. */ - if (unlikely(!vm->root_page_table)) { + if (unlikely(!as->pt.root)) { + struct device *dev =3D drm_dev_dma_dev(ddev); struct page *p; =20 - drm_WARN_ON(&vm->ptdev->base, vm->op_ctx); - p =3D alloc_pages_node(dev_to_node(vm->ptdev->base.dev), - gfp | __GFP_ZERO, get_order(size)); + drm_WARN_ON(ddev, op_ctx); + p =3D alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, get_order(siz= e)); page =3D p ? page_address(p) : NULL; - vm->root_page_table =3D page; + as->pt.root =3D page; return page; } =20 /* We're not supposed to have anything bigger than 4k here, because we pi= cked a * 4k granule size at init time. */ - if (drm_WARN_ON(&vm->ptdev->base, size !=3D SZ_4K)) + if (drm_WARN_ON(ddev, size !=3D SZ_4K)) return NULL; =20 /* We must have some op_ctx attached to the VM and it must have at least = one * free page. */ - if (drm_WARN_ON(&vm->ptdev->base, !vm->op_ctx) || - drm_WARN_ON(&vm->ptdev->base, - vm->op_ctx->rsvd_page_tables.ptr >=3D vm->op_ctx->rsvd_page_tables.coun= t)) + if (drm_WARN_ON(ddev, !op_ctx) || + drm_WARN_ON(ddev, op_ctx->rsvd_page_tables.ptr >=3D op_ctx->rsvd_page= _tables.count)) return NULL; =20 - page =3D vm->op_ctx->rsvd_page_tables.pages[vm->op_ctx->rsvd_page_tables.= ptr++]; + page =3D op_ctx->rsvd_page_tables.pages[op_ctx->rsvd_page_tables.ptr++]; memset(page, 0, SZ_4K); =20 /* Page table entries don't use virtual addresses, which trips out @@ -518,22 +527,23 @@ static void *alloc_pt(void *cookie, size_t size, gfp_= t gfp) */ static void free_pt(void *cookie, void *data, size_t size) { - struct panthor_vm *vm =3D cookie; + struct panthor_as *as =3D cookie; + struct drm_device *ddev =3D as->base.drm; =20 - if (unlikely(vm->root_page_table =3D=3D data)) { + if (unlikely(as->pt.root =3D=3D data)) { free_pages((unsigned long)data, get_order(size)); - vm->root_page_table =3D NULL; + as->pt.root =3D NULL; return; } =20 - if (drm_WARN_ON(&vm->ptdev->base, size !=3D SZ_4K)) + if (drm_WARN_ON(ddev, size !=3D SZ_4K)) return; =20 /* Return the page to the pt_cache. */ kmem_cache_free(pt_cache, data); } =20 -static int wait_ready(struct panthor_device *ptdev, u32 as_nr) +static int wait_ready(struct panthor_device *ptdev, u32 slot) { struct panthor_mmu *mmu =3D ptdev->mmu; int ret; @@ -542,7 +552,7 @@ static int wait_ready(struct panthor_device *ptdev, u32= as_nr) /* Wait for the MMU status to indicate there is no active command, in * case one is pending. */ - ret =3D gpu_read_relaxed_poll_timeout_atomic(mmu->iomem, AS_STATUS(as_nr)= , val, + ret =3D gpu_read_relaxed_poll_timeout_atomic(mmu->iomem, AS_STATUS(slot),= val, !(val & AS_STATUS_AS_ACTIVE), 10, 100000); =20 if (ret) { @@ -553,15 +563,15 @@ static int wait_ready(struct panthor_device *ptdev, u= 32 as_nr) return ret; } =20 -static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 as_nr, u= 32 cmd) +static int as_send_cmd_and_wait(struct panthor_device *ptdev, u32 slot, u3= 2 cmd) { int status; =20 /* write AS_COMMAND when MMU is ready to accept another command */ - status =3D wait_ready(ptdev, as_nr); + status =3D wait_ready(ptdev, slot); if (!status) { - gpu_write(ptdev->mmu->iomem, AS_COMMAND(as_nr), cmd); - status =3D wait_ready(ptdev, as_nr); + gpu_write(ptdev->mmu->iomem, AS_COMMAND(slot), cmd); + status =3D wait_ready(ptdev, slot); } =20 return status; @@ -596,41 +606,41 @@ static u64 pack_region_range(struct panthor_device *p= tdev, u64 *region_start, u6 return region_width | *region_start; } =20 -static u32 panthor_mmu_as_fault_mask(struct panthor_device *ptdev, u32 as) +static u32 panthor_mmu_as_fault_mask(struct panthor_device *ptdev, u32 slo= t) { - return BIT(as); + return BIT(slot); } =20 /* Forward declaration to call helpers within as_enable/disable */ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 stat= us); PANTHOR_IRQ_HANDLER(mmu, panthor_mmu_irq_handler); =20 -static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, +static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 slot, u64 transtab, u64 transcfg, u64 memattr) { struct panthor_mmu *mmu =3D ptdev->mmu; =20 panthor_mmu_irq_enable_events(&ptdev->mmu->irq, - panthor_mmu_as_fault_mask(ptdev, as_nr)); + panthor_mmu_as_fault_mask(ptdev, slot)); =20 - gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), transtab); - gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), memattr); - gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), transcfg); + gpu_write64(mmu->iomem, AS_TRANSTAB(slot), transtab); + gpu_write64(mmu->iomem, AS_MEMATTR(slot), memattr); + gpu_write64(mmu->iomem, AS_TRANSCFG(slot), transcfg); =20 - return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); + return as_send_cmd_and_wait(ptdev, slot, AS_COMMAND_UPDATE); } =20 -static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr, +static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 slot, bool recycle_slot) { struct panthor_mmu *mmu =3D ptdev->mmu; - struct panthor_vm *vm =3D ptdev->mmu->as.slots[as_nr].vm; + struct panthor_as *as =3D ptdev->mmu->as.slots[slot].as; int ret; =20 lockdep_assert_held(&ptdev->mmu->as.slots_lock); =20 panthor_mmu_irq_disable_events(&ptdev->mmu->irq, - panthor_mmu_as_fault_mask(ptdev, as_nr)); + panthor_mmu_as_fault_mask(ptdev, slot)); =20 /* Flush+invalidate RW caches, invalidate RO ones. */ ret =3D panthor_gpu_flush_caches(ptdev, CACHE_CLEAN | CACHE_INV, @@ -638,9 +648,9 @@ static int panthor_mmu_as_disable(struct panthor_device= *ptdev, u32 as_nr, if (ret) return ret; =20 - if (vm && vm->locked_region.size) { + if (as && as->locked_region.size) { /* Unlock the region if there's a lock pending. */ - ret =3D as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_UNLOCK); + ret =3D as_send_cmd_and_wait(ptdev, slot, AS_COMMAND_UNLOCK); if (ret) return ret; } @@ -651,11 +661,11 @@ static int panthor_mmu_as_disable(struct panthor_devi= ce *ptdev, u32 as_nr, if (recycle_slot) return 0; =20 - gpu_write64(mmu->iomem, AS_TRANSTAB(as_nr), 0); - gpu_write64(mmu->iomem, AS_MEMATTR(as_nr), 0); - gpu_write64(mmu->iomem, AS_TRANSCFG(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); + gpu_write64(mmu->iomem, AS_TRANSTAB(slot), 0); + gpu_write64(mmu->iomem, AS_MEMATTR(slot), 0); + gpu_write64(mmu->iomem, AS_TRANSCFG(slot), AS_TRANSCFG_ADRMODE_UNMAPPED); =20 - return as_send_cmd_and_wait(ptdev, as_nr, AS_COMMAND_UPDATE); + return as_send_cmd_and_wait(ptdev, slot, AS_COMMAND_UPDATE); } =20 static u32 panthor_mmu_fault_mask(struct panthor_device *ptdev, u32 value) @@ -672,7 +682,7 @@ static u32 panthor_mmu_fault_mask(struct panthor_device= *ptdev, u32 value) */ bool panthor_vm_has_unhandled_faults(struct panthor_vm *vm) { - return vm->unhandled_fault; + return vm->as->unhandled_fault; } =20 /** @@ -683,23 +693,23 @@ bool panthor_vm_has_unhandled_faults(struct panthor_v= m *vm) */ bool panthor_vm_is_unusable(struct panthor_vm *vm) { - return vm->unusable; + return vm->as->unusable; } =20 -static void panthor_vm_release_as_locked(struct panthor_vm *vm) +static void panthor_as_release_hw_slot_locked(struct panthor_as *as) { - struct panthor_device *ptdev =3D vm->ptdev; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); =20 lockdep_assert_held(&ptdev->mmu->as.slots_lock); =20 - if (drm_WARN_ON(&ptdev->base, vm->as.id < 0)) + if (drm_WARN_ON(&ptdev->base, as->hw_slot.id < 0)) return; =20 - ptdev->mmu->as.slots[vm->as.id].vm =3D NULL; - clear_bit(vm->as.id, &ptdev->mmu->as.alloc_mask); - refcount_set(&vm->as.active_cnt, 0); - list_del_init(&vm->as.lru_node); - vm->as.id =3D -1; + ptdev->mmu->as.slots[as->hw_slot.id].as =3D NULL; + clear_bit(as->hw_slot.id, &ptdev->mmu->as.alloc_mask); + refcount_set(&as->active_cnt, 0); + list_del_init(&as->hw_slot.lru_node); + as->hw_slot.id =3D -1; } =20 /** @@ -712,17 +722,18 @@ static void panthor_vm_release_as_locked(struct panth= or_vm *vm) */ int panthor_vm_active(struct panthor_vm *vm) { - struct panthor_device *ptdev =3D vm->ptdev; + struct panthor_as *as =3D vm->as; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); u32 va_bits =3D GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features); - struct io_pgtable_cfg *cfg =3D &io_pgtable_ops_to_pgtable(vm->pgtbl_ops)-= >cfg; - int ret =3D 0, as, cookie; + struct io_pgtable_cfg *cfg =3D &io_pgtable_ops_to_pgtable(as->pt.ops)->cf= g; + int ret =3D 0, slot, cookie; u64 transtab, transcfg; u32 fault_mask; =20 if (!drm_dev_enter(&ptdev->base, &cookie)) return -ENODEV; =20 - if (refcount_inc_not_zero(&vm->as.active_cnt)) + if (refcount_inc_not_zero(&as->active_cnt)) goto out_dev_exit; =20 /* As soon as active is called, we place the VM at the end of the VM LRU. @@ -731,25 +742,25 @@ int panthor_vm_active(struct panthor_vm *vm) * that's an acceptable trade-off. */ mutex_lock(&ptdev->base.gem_lru_mutex); - if (vm->reclaim.lru.count) - list_move_tail(&vm->reclaim.lru_node, &ptdev->reclaim.vms); + if (as->reclaim.lru.count) + list_move_tail(&as->reclaim.lru_node, &ptdev->reclaim.vms); mutex_unlock(&ptdev->base.gem_lru_mutex); =20 /* Make sure we don't race with lock/unlock_region() calls * happening around VM bind operations. */ - mutex_lock(&vm->op_lock); + mutex_lock(&as->op_lock); mutex_lock(&ptdev->mmu->as.slots_lock); =20 - if (refcount_inc_not_zero(&vm->as.active_cnt)) + if (refcount_inc_not_zero(&as->active_cnt)) goto out_unlock; =20 - as =3D vm->as.id; - if (as >=3D 0) { + slot =3D as->hw_slot.id; + if (slot >=3D 0) { /* Unhandled pagefault on this AS, the MMU was disabled. We need to * re-enable the MMU after clearing+unmasking the AS interrupts. */ - if (ptdev->mmu->as.faulty_mask & panthor_mmu_as_fault_mask(ptdev, as)) + if (ptdev->mmu->as.faulty_mask & panthor_mmu_as_fault_mask(ptdev, slot)) goto out_enable_as; =20 goto out_make_active; @@ -758,36 +769,36 @@ int panthor_vm_active(struct panthor_vm *vm) /* Check for a free AS */ if (vm->for_mcu) { drm_WARN_ON(&ptdev->base, ptdev->mmu->as.alloc_mask & BIT(0)); - as =3D 0; + slot =3D 0; } else { - as =3D ffz(ptdev->mmu->as.alloc_mask | BIT(0)); + slot =3D ffz(ptdev->mmu->as.alloc_mask | BIT(0)); } =20 - if (!(BIT(as) & ptdev->gpu_info.as_present)) { - struct panthor_vm *lru_vm; + if (!(BIT(slot) & ptdev->gpu_info.as_present)) { + struct panthor_as *lru_as; =20 - lru_vm =3D list_first_entry_or_null(&ptdev->mmu->as.lru_list, - struct panthor_vm, - as.lru_node); - if (drm_WARN_ON(&ptdev->base, !lru_vm)) { + lru_as =3D list_first_entry_or_null(&ptdev->mmu->as.lru_list, + struct panthor_as, + hw_slot.lru_node); + if (drm_WARN_ON(&ptdev->base, !lru_as)) { ret =3D -EBUSY; goto out_unlock; } =20 - drm_WARN_ON(&ptdev->base, refcount_read(&lru_vm->as.active_cnt)); - as =3D lru_vm->as.id; + drm_WARN_ON(&ptdev->base, refcount_read(&lru_as->active_cnt)); + slot =3D lru_as->hw_slot.id; =20 - ret =3D panthor_mmu_as_disable(ptdev, as, true); + ret =3D panthor_mmu_as_disable(ptdev, slot, true); if (ret) goto out_unlock; =20 - panthor_vm_release_as_locked(lru_vm); + panthor_as_release_hw_slot_locked(lru_as); } =20 /* Assign the free or reclaimed AS to the FD */ - vm->as.id =3D as; - set_bit(as, &ptdev->mmu->as.alloc_mask); - ptdev->mmu->as.slots[as].vm =3D vm; + as->hw_slot.id =3D slot; + set_bit(slot, &ptdev->mmu->as.alloc_mask); + ptdev->mmu->as.slots[slot].as =3D as; =20 out_enable_as: transtab =3D cfg->arm_lpae_s1_cfg.ttbr; @@ -799,12 +810,12 @@ int panthor_vm_active(struct panthor_vm *vm) transcfg |=3D AS_TRANSCFG_PTW_SH_OS; =20 /* If the VM is re-activated, we clear the fault. */ - vm->unhandled_fault =3D false; + as->unhandled_fault =3D false; =20 /* Unhandled pagefault on this AS, clear the fault and enable the AS, * which re-enables interrupts. */ - fault_mask =3D panthor_mmu_as_fault_mask(ptdev, as); + fault_mask =3D panthor_mmu_as_fault_mask(ptdev, slot); if (ptdev->mmu->as.faulty_mask & fault_mask) { gpu_write(ptdev->mmu->irq.iomem, INT_CLEAR, fault_mask); ptdev->mmu->as.faulty_mask &=3D ~fault_mask; @@ -813,18 +824,18 @@ int panthor_vm_active(struct panthor_vm *vm) /* The VM update is guarded by ::op_lock, which we take at the beginning * of this function, so we don't expect any locked region here. */ - drm_WARN_ON(&vm->ptdev->base, vm->locked_region.size > 0); - ret =3D panthor_mmu_as_enable(vm->ptdev, vm->as.id, transtab, transcfg, v= m->memattr); + drm_WARN_ON(&ptdev->base, as->locked_region.size > 0); + ret =3D panthor_mmu_as_enable(ptdev, as->hw_slot.id, transtab, transcfg, = as->memattr); =20 out_make_active: if (!ret) { - refcount_set(&vm->as.active_cnt, 1); - list_del_init(&vm->as.lru_node); + refcount_set(&as->active_cnt, 1); + list_del_init(&as->hw_slot.lru_node); } =20 out_unlock: mutex_unlock(&ptdev->mmu->as.slots_lock); - mutex_unlock(&vm->op_lock); + mutex_unlock(&as->op_lock); =20 out_dev_exit: drm_dev_exit(cookie); @@ -846,21 +857,22 @@ int panthor_vm_active(struct panthor_vm *vm) */ void panthor_vm_idle(struct panthor_vm *vm) { - struct panthor_device *ptdev =3D vm->ptdev; + struct panthor_as *as =3D vm->as; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); =20 - if (!refcount_dec_and_mutex_lock(&vm->as.active_cnt, &ptdev->mmu->as.slot= s_lock)) + if (!refcount_dec_and_mutex_lock(&as->active_cnt, &ptdev->mmu->as.slots_l= ock)) return; =20 - if (!drm_WARN_ON(&ptdev->base, vm->as.id =3D=3D -1 || !list_empty(&vm->as= .lru_node))) - list_add_tail(&vm->as.lru_node, &ptdev->mmu->as.lru_list); + if (!drm_WARN_ON(&ptdev->base, as->hw_slot.id =3D=3D -1 || !list_empty(&a= s->hw_slot.lru_node))) + list_add_tail(&as->hw_slot.lru_node, &ptdev->mmu->as.lru_list); =20 - refcount_set(&vm->as.active_cnt, 0); + refcount_set(&as->active_cnt, 0); mutex_unlock(&ptdev->mmu->as.slots_lock); } =20 u32 panthor_vm_page_size(struct panthor_vm *vm) { - const struct io_pgtable *pgt =3D io_pgtable_ops_to_pgtable(vm->pgtbl_ops); + const struct io_pgtable *pgt =3D io_pgtable_ops_to_pgtable(vm->as->pt.ops= ); u32 pg_shift =3D ffs(pgt->cfg.pgsize_bitmap) - 1; =20 return 1u << pg_shift; @@ -884,7 +896,7 @@ static void panthor_vm_start(struct panthor_vm *vm) */ int panthor_vm_as(struct panthor_vm *vm) { - return vm->as.id; + return vm->as->hw_slot.id; } =20 static size_t get_pgsize(u64 addr, size_t size, size_t *count) @@ -908,43 +920,43 @@ static size_t get_pgsize(u64 addr, size_t size, size_= t *count) return SZ_2M; } =20 -static void panthor_vm_declare_unusable(struct panthor_vm *vm) +static void panthor_as_declare_unusable(struct panthor_as *as) { - struct panthor_device *ptdev =3D vm->ptdev; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); int cookie; =20 - if (vm->unusable) + if (as->unusable) return; =20 - vm->unusable =3D true; + as->unusable =3D true; mutex_lock(&ptdev->mmu->as.slots_lock); - if (vm->as.id >=3D 0 && drm_dev_enter(&ptdev->base, &cookie)) { - panthor_mmu_as_disable(ptdev, vm->as.id, false); + if (as->hw_slot.id >=3D 0 && drm_dev_enter(&ptdev->base, &cookie)) { + panthor_mmu_as_disable(ptdev, as->hw_slot.id, false); drm_dev_exit(cookie); } mutex_unlock(&ptdev->mmu->as.slots_lock); } =20 -static void panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 si= ze) +static void panthor_as_unmap_pages(struct panthor_as *as, u64 iova, u64 si= ze) { - struct panthor_device *ptdev =3D vm->ptdev; - struct io_pgtable_ops *ops =3D vm->pgtbl_ops; + struct drm_device *ddev =3D as->base.drm; + struct io_pgtable_ops *ops =3D as->pt.ops; u64 start_iova =3D iova; u64 offset =3D 0; =20 if (!size) return; =20 - drm_WARN_ON(&ptdev->base, - (iova < vm->locked_region.start) || - (iova + size > vm->locked_region.start + vm->locked_region.size)); + drm_WARN_ON(ddev, + (iova < as->locked_region.start) || + (iova + size > as->locked_region.start + as->locked_region.size)); =20 while (offset < size) { size_t unmapped_sz =3D 0, pgcount; size_t pgsize =3D get_pgsize(iova + offset, size - offset, &pgcount); =20 unmapped_sz =3D ops->unmap_pages(ops, iova + offset, pgsize, pgcount, NU= LL); - if (drm_WARN_ON_ONCE(&ptdev->base, unmapped_sz !=3D pgsize * pgcount)) { + if (drm_WARN_ON_ONCE(ddev, unmapped_sz !=3D pgsize * pgcount)) { /* Gracefully handle sparsely unmapped regions to avoid leaving * page table pages behind when the drm_gpuvm and VM page table * are out-of-sync. This is not supposed to happen, hence the @@ -958,33 +970,32 @@ static void panthor_vm_unmap_pages(struct panthor_vm = *vm, u64 iova, u64 size) * so flag the VM unusable to make sure it's not going * to be used anymore. */ - panthor_vm_declare_unusable(vm); + panthor_as_declare_unusable(as); =20 /* If we don't make progress, we're screwed. That also means * something else prevents us from unmapping the region, but * there's not much we can do here: time for debugging. */ - if (drm_WARN_ON_ONCE(&ptdev->base, !unmapped_sz)) + if (drm_WARN_ON_ONCE(ddev, !unmapped_sz)) return; } =20 - drm_dbg(&ptdev->base, - "unmap: as=3D%d, iova=3D0x%llx, sz=3D%llu, va=3D0x%llx, pgcnt=3D%zu, pg= sz=3D%zu", - vm->as.id, start_iova, size, iova + offset, - unmapped_sz / pgsize, pgsize); + drm_dbg(ddev, + "unmap: iova=3D0x%llx, sz=3D%llu, va=3D0x%llx, pgcnt=3D%zu, pgsz=3D%zu", + start_iova, size, iova + offset, unmapped_sz / pgsize, pgsize); =20 offset +=3D unmapped_sz; } } =20 static int -panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot, +panthor_as_map_pages(struct panthor_as *as, u64 iova, int prot, struct sg_table *sgt, u64 offset, u64 size) { - struct panthor_device *ptdev =3D vm->ptdev; + struct drm_device *ddev =3D as->base.drm; unsigned int count; struct scatterlist *sgl; - struct io_pgtable_ops *ops =3D vm->pgtbl_ops; + struct io_pgtable_ops *ops =3D as->pt.ops; u64 start_iova =3D iova; u64 start_size =3D size; int ret; @@ -992,9 +1003,9 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, = int prot, if (!size) return 0; =20 - drm_WARN_ON(&ptdev->base, - (iova < vm->locked_region.start) || - (iova + size > vm->locked_region.start + vm->locked_region.size)); + drm_WARN_ON(ddev, + (iova < as->locked_region.start) || + (iova + size > as->locked_region.start + as->locked_region.size)); =20 for_each_sgtable_dma_sg(sgt, sgl, count) { dma_addr_t paddr =3D sg_dma_address(sgl); @@ -1017,10 +1028,9 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova= , int prot, ret =3D ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, GFP_KERNEL, &mapped); =20 - drm_dbg(&ptdev->base, - "map: as=3D%d, iova=3D0x%llx, sz=3D%llu, va=3D0x%llx, pa=3D%pad, pgcnt= =3D%zu, pgsz=3D%zu", - vm->as.id, start_iova, start_size, iova, &paddr, - mapped / pgsize, pgsize); + drm_dbg(ddev, + "map: iova=3D0x%llx, sz=3D%llu, va=3D0x%llx, pa=3D%pad, pgcnt=3D%zu, p= gsz=3D%zu", + start_iova, start_size, iova, &paddr, mapped / pgsize, pgsize); =20 iova +=3D mapped; paddr +=3D mapped; @@ -1031,12 +1041,12 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iov= a, int prot, ret =3D -ENOMEM; =20 /* If something fails, we stop there, and flag the VM unusable. */ - if (drm_WARN_ON_ONCE(&ptdev->base, ret)) { + if (drm_WARN_ON_ONCE(ddev, ret)) { /* Unmap what we've already mapped to avoid leaving page * table pages behind. */ - panthor_vm_unmap_pages(vm, start_iova, iova - start_iova); - panthor_vm_declare_unusable(vm); + panthor_as_unmap_pages(as, start_iova, iova - start_iova); + panthor_as_declare_unusable(as); return ret; } } @@ -1051,8 +1061,8 @@ panthor_vm_map_pages(struct panthor_vm *vm, u64 iova,= int prot, } =20 static int -panthor_vm_map_sparse(struct panthor_vm *vm, u64 iova, int prot, - struct sg_table *sgt, u64 size) +panthor_as_map_sparse(struct panthor_as *as, u64 iova, + int prot, struct sg_table *sgt, u64 size) { u64 mapped =3D 0; int ret; @@ -1061,10 +1071,10 @@ panthor_vm_map_sparse(struct panthor_vm *vm, u64 io= va, int prot, u64 addr =3D iova + mapped; u32 chunk_size =3D min(size - mapped, SZ_2M - (addr & (SZ_2M - 1))); =20 - ret =3D panthor_vm_map_pages(vm, addr, prot, sgt, + ret =3D panthor_as_map_pages(as, addr, prot, sgt, addr % SZ_2M, chunk_size); if (ret) { - panthor_vm_unmap_pages(vm, iova, mapped); + panthor_as_unmap_pages(as, iova, mapped); return ret; } =20 @@ -1166,8 +1176,8 @@ static void panthor_vm_bo_free(struct drm_gpuvm_bo *v= m_bo) kfree(vm_bo); } =20 -static void panthor_vm_cleanup_op_ctx(struct panthor_vm_op_ctx *op_ctx, - struct panthor_vm *vm) +static void panthor_as_cleanup_op_ctx(struct panthor_as_op_ctx *op_ctx, + struct panthor_as *as) { u32 remaining_pt_count =3D op_ctx->rsvd_page_tables.count - op_ctx->rsvd_page_tables.ptr; @@ -1202,11 +1212,11 @@ static void panthor_vm_cleanup_op_ctx(struct pantho= r_vm_op_ctx *op_ctx, kfree(op_ctx->preallocated_vmas[i]); =20 if (!skip_deferred_cleanup) - drm_gpuvm_bo_deferred_cleanup(&vm->base); + drm_gpuvm_bo_deferred_cleanup(&as->base); } =20 static void -panthor_vm_op_ctx_return_vma(struct panthor_vm_op_ctx *op_ctx, +panthor_as_op_ctx_return_vma(struct panthor_as_op_ctx *op_ctx, struct panthor_vma *vma) { for (u32 i =3D 0; i < ARRAY_SIZE(op_ctx->preallocated_vmas); i++) { @@ -1220,7 +1230,7 @@ panthor_vm_op_ctx_return_vma(struct panthor_vm_op_ctx= *op_ctx, } =20 static struct panthor_vma * -panthor_vm_op_ctx_get_vma(struct panthor_vm_op_ctx *op_ctx) +panthor_as_op_ctx_get_vma(struct panthor_as_op_ctx *op_ctx) { for (u32 i =3D 0; i < ARRAY_SIZE(op_ctx->preallocated_vmas); i++) { struct panthor_vma *vma =3D op_ctx->preallocated_vmas[i]; @@ -1235,7 +1245,7 @@ panthor_vm_op_ctx_get_vma(struct panthor_vm_op_ctx *o= p_ctx) } =20 static int -panthor_vm_op_ctx_prealloc_vmas(struct panthor_vm_op_ctx *op_ctx) +panthor_as_op_ctx_prealloc_vmas(struct panthor_as_op_ctx *op_ctx) { u32 vma_count; =20 @@ -1274,7 +1284,7 @@ panthor_vm_op_ctx_prealloc_vmas(struct panthor_vm_op_= ctx *op_ctx) return 0; } =20 -static void panthor_vm_init_op_ctx(struct panthor_vm_op_ctx *op_ctx, +static void panthor_vm_init_op_ctx(struct panthor_as_op_ctx *op_ctx, u64 size, u64 va, u32 flags) { memset(op_ctx, 0, sizeof(*op_ctx)); @@ -1283,7 +1293,7 @@ static void panthor_vm_init_op_ctx(struct panthor_vm_= op_ctx *op_ctx, op_ctx->va.addr =3D va; } =20 -static int panthor_vm_op_ctx_prealloc_pts(struct panthor_vm_op_ctx *op_ctx) +static int panthor_as_op_ctx_prealloc_pts(struct panthor_as_op_ctx *op_ctx) { u64 size =3D op_ctx->va.range; u64 va =3D op_ctx->va.addr; @@ -1319,8 +1329,8 @@ static int panthor_vm_op_ctx_prealloc_pts(struct pant= hor_vm_op_ctx *op_ctx) DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE | \ DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) =20 -static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, - struct panthor_vm *vm, +static int panthor_as_prepare_map_op_ctx(struct panthor_as_op_ctx *op_ctx, + struct panthor_as *as, struct panthor_gem_object *bo, const struct drm_panthor_vm_bind_op *op) { @@ -1355,12 +1365,12 @@ static int panthor_vm_prepare_map_op_ctx(struct pan= thor_vm_op_ctx *op_ctx, =20 /* If the BO has an exclusive VM attached, it can't be mapped to other VM= s. */ if (bo->exclusive_vm_root_gem && - bo->exclusive_vm_root_gem !=3D panthor_vm_root_gem(vm)) + bo->exclusive_vm_root_gem !=3D as->base.r_obj) return -EINVAL; =20 panthor_vm_init_op_ctx(op_ctx, op->size, op->va, op->flags); =20 - ret =3D panthor_vm_op_ctx_prealloc_vmas(op_ctx); + ret =3D panthor_as_op_ctx_prealloc_vmas(op_ctx); if (ret) goto err_cleanup; =20 @@ -1380,7 +1390,7 @@ static int panthor_vm_prepare_map_op_ctx(struct panth= or_vm_op_ctx *op_ctx, goto err_cleanup; } =20 - preallocated_vm_bo =3D drm_gpuvm_bo_create(&vm->base, &bo->base); + preallocated_vm_bo =3D drm_gpuvm_bo_create(&as->base, &bo->base); if (!preallocated_vm_bo) { ret =3D -ENOMEM; goto err_cleanup; @@ -1389,15 +1399,15 @@ static int panthor_vm_prepare_map_op_ctx(struct pan= thor_vm_op_ctx *op_ctx, op_ctx->map.vm_bo =3D drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo); op_ctx->map.bo_offset =3D op->bo_offset; =20 - ret =3D panthor_vm_op_ctx_prealloc_pts(op_ctx); + ret =3D panthor_as_op_ctx_prealloc_pts(op_ctx); if (ret) goto err_cleanup; =20 /* Insert BO into the extobj list last, when we know nothing can fail. */ - if (bo->base.resv !=3D panthor_vm_resv(vm)) { - dma_resv_lock(panthor_vm_resv(vm), NULL); + if (bo->base.resv !=3D drm_gpuvm_resv(&as->base)) { + dma_resv_lock(drm_gpuvm_resv(&as->base), NULL); drm_gpuvm_bo_extobj_add(op_ctx->map.vm_bo); - dma_resv_unlock(panthor_vm_resv(vm)); + dma_resv_unlock(drm_gpuvm_resv(&as->base)); } =20 /* And finally update the BO state. */ @@ -1410,12 +1420,12 @@ static int panthor_vm_prepare_map_op_ctx(struct pan= thor_vm_op_ctx *op_ctx, return 0; =20 err_cleanup: - panthor_vm_cleanup_op_ctx(op_ctx, vm); + panthor_as_cleanup_op_ctx(op_ctx, as); return ret; } =20 -static int panthor_vm_prepare_unmap_op_ctx(struct panthor_vm_op_ctx *op_ct= x, - struct panthor_vm *vm, +static int panthor_as_prepare_unmap_op_ctx(struct panthor_as_op_ctx *op_ct= x, + struct panthor_as *as, u64 va, u64 size) { u32 pt_count =3D 0; @@ -1436,7 +1446,7 @@ static int panthor_vm_prepare_unmap_op_ctx(struct pan= thor_vm_op_ctx *op_ctx, ALIGN(va + size, SZ_2M) !=3D ALIGN(va, SZ_2M)) pt_count++; =20 - ret =3D panthor_vm_op_ctx_prealloc_vmas(op_ctx); + ret =3D panthor_as_op_ctx_prealloc_vmas(op_ctx); if (ret) goto err_cleanup; =20 @@ -1459,12 +1469,12 @@ static int panthor_vm_prepare_unmap_op_ctx(struct p= anthor_vm_op_ctx *op_ctx, return 0; =20 err_cleanup: - panthor_vm_cleanup_op_ctx(op_ctx, vm); + panthor_as_cleanup_op_ctx(op_ctx, as); return ret; } =20 static void -panthor_vm_prepare_sync_only_op_ctx(struct panthor_vm_op_ctx *op_ctx) +panthor_as_prepare_sync_only_op_ctx(struct panthor_as_op_ctx *op_ctx) { memset(op_ctx, 0, sizeof(*op_ctx)); op_ctx->flags =3D DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY; @@ -1492,8 +1502,8 @@ panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 v= a, u64 *bo_offset) struct panthor_vma *vma; =20 /* Take the VM lock to prevent concurrent map/unmap operations. */ - mutex_lock(&vm->op_lock); - gpuva =3D drm_gpuva_find_first(&vm->base, va, 1); + mutex_lock(&vm->as->op_lock); + gpuva =3D drm_gpuva_find_first(&vm->as->base, va, 1); vma =3D gpuva ? container_of(gpuva, struct panthor_vma, base) : NULL; if (vma && vma->base.gem.obj) { drm_gem_object_get(vma->base.gem.obj); @@ -1502,7 +1512,7 @@ panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 v= a, u64 *bo_offset) vma->base.gem.offset + (va - vma->base.va.addr) : va & (SZ_2M - 1); } - mutex_unlock(&vm->op_lock); + mutex_unlock(&vm->as->op_lock); =20 return bo; } @@ -1622,22 +1632,24 @@ int panthor_vm_pool_create_vm(struct panthor_device= *ptdev, =20 static void panthor_vm_destroy(struct panthor_vm *vm) { + struct panthor_as *as; + struct panthor_device *ptdev; + if (!vm) return; =20 + as =3D vm->as; + ptdev =3D container_of(as->base.drm, struct panthor_device, base); vm->destroyed =3D true; =20 /* Tell scheduler to stop all GPU work related to this VM */ - if (refcount_read(&vm->as.active_cnt) > 0) - panthor_sched_prepare_for_vm_destruction(vm->ptdev); + if (refcount_read(&as->active_cnt) > 0) + panthor_sched_prepare_for_vm_destruction(ptdev); =20 mutex_lock(&vm->heaps.lock); panthor_heap_pool_destroy(vm->heaps.pool); vm->heaps.pool =3D NULL; mutex_unlock(&vm->heaps.lock); - - drm_WARN_ON(&vm->ptdev->base, - panthor_vm_unmap_range(vm, vm->base.mm_start, vm->base.mm_range)); panthor_vm_put(vm); } =20 @@ -1777,17 +1789,18 @@ static const char *access_type_name(struct panthor_= device *ptdev, } } =20 -static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 si= ze) +static int panthor_as_lock_region(struct panthor_as *as, u64 start, u64 si= ze) { - struct panthor_device *ptdev =3D vm->ptdev; + struct drm_device *ddev =3D as->base.drm; + struct panthor_device *ptdev =3D container_of(ddev, struct panthor_device= , base); int ret =3D 0; =20 - /* sm_step_remap() can call panthor_vm_lock_region() to account for + /* sm_step_remap() can call panthor_as_lock_region() to account for * the wider unmap needed when doing a partial huge page unamp. We * need to ignore the lock if it's already part of the locked region. */ - if (start >=3D vm->locked_region.start && - start + size <=3D vm->locked_region.start + vm->locked_region.size) + if (start >=3D as->locked_region.start && + start + size <=3D as->locked_region.start + as->locked_region.size) return 0; =20 /* sm_step_remap() may need a locked region that isn't a strict superset @@ -1798,42 +1811,42 @@ static int panthor_vm_lock_region(struct panthor_vm= *vm, u64 start, u64 size) * boundaries in a remap operation can only shift up or down respectively, * but never otherwise. */ - if (vm->locked_region.size) { - u64 end =3D max(vm->locked_region.start + vm->locked_region.size, + if (as->locked_region.size) { + u64 end =3D max(as->locked_region.start + as->locked_region.size, start + size); =20 - drm_WARN_ON_ONCE(&vm->ptdev->base, (start + size <=3D vm->locked_region.= start) || - (start >=3D vm->locked_region.start + vm->locked_region.size)); + drm_WARN_ON_ONCE(ddev, (start + size <=3D as->locked_region.start) || + (start >=3D as->locked_region.start + as->locked_region.size)); =20 - start =3D min(start, vm->locked_region.start); + start =3D min(start, as->locked_region.start); size =3D end - start; } =20 mutex_lock(&ptdev->mmu->as.slots_lock); - if (vm->as.id >=3D 0 && size) { + if (as->hw_slot.id >=3D 0 && size) { /* Lock the region that needs to be updated */ - gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(vm->as.id), + gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(as->hw_slot.id), pack_region_range(ptdev, &start, &size)); =20 /* If the lock succeeded, update the locked_region info. */ - ret =3D as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_LOCK); + ret =3D as_send_cmd_and_wait(ptdev, as->hw_slot.id, AS_COMMAND_LOCK); } =20 if (!ret) { - vm->locked_region.start =3D start; - vm->locked_region.size =3D size; + as->locked_region.start =3D start; + as->locked_region.size =3D size; } mutex_unlock(&ptdev->mmu->as.slots_lock); =20 return ret; } =20 -static void panthor_vm_unlock_region(struct panthor_vm *vm) +static void panthor_as_unlock_region(struct panthor_as *as) { - struct panthor_device *ptdev =3D vm->ptdev; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); =20 mutex_lock(&ptdev->mmu->as.slots_lock); - if (vm->as.id >=3D 0) { + if (as->hw_slot.id >=3D 0) { int ret; =20 /* flush+invalidate RW caches and invalidate RO ones. @@ -1846,7 +1859,7 @@ static void panthor_vm_unlock_region(struct panthor_v= m *vm) =20 /* Unlock the region if the flush is effective. */ if (!ret) - ret =3D as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_UNLOCK); + ret =3D as_send_cmd_and_wait(ptdev, as->hw_slot.id, AS_COMMAND_UNLOCK); =20 /* If we fail to flush or unlock the region, schedule a GPU reset * to unblock the situation. @@ -1854,8 +1867,8 @@ static void panthor_vm_unlock_region(struct panthor_v= m *vm) if (ret) panthor_device_schedule_reset(ptdev); } - vm->locked_region.start =3D 0; - vm->locked_region.size =3D 0; + as->locked_region.start =3D 0; + as->locked_region.size =3D 0; mutex_unlock(&ptdev->mmu->as.slots_lock); } =20 @@ -1908,8 +1921,8 @@ static void panthor_mmu_irq_handler(struct panthor_de= vice *ptdev, u32 status) */ gpu_write(mmu->irq.iomem, INT_CLEAR, mask); =20 - if (ptdev->mmu->as.slots[as].vm) - ptdev->mmu->as.slots[as].vm->unhandled_fault =3D true; + if (ptdev->mmu->as.slots[as].as) + ptdev->mmu->as.slots[as].as->unhandled_fault =3D true; =20 /* Disable the MMU to kill jobs on this AS. */ panthor_mmu_as_disable(ptdev, as, false); @@ -1937,12 +1950,12 @@ void panthor_mmu_suspend(struct panthor_device *ptd= ev) { mutex_lock(&ptdev->mmu->as.slots_lock); for (u32 i =3D 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { - struct panthor_vm *vm =3D ptdev->mmu->as.slots[i].vm; + struct panthor_as *as =3D ptdev->mmu->as.slots[i].as; =20 - if (vm) { + if (as) { drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i, false)); - panthor_vm_release_as_locked(vm); + panthor_as_release_hw_slot_locked(as); } } mutex_unlock(&ptdev->mmu->as.slots_lock); @@ -2012,10 +2025,10 @@ void panthor_mmu_post_reset(struct panthor_device *= ptdev) ptdev->mmu->as.faulty_mask =3D 0; =20 for (u32 i =3D 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { - struct panthor_vm *vm =3D ptdev->mmu->as.slots[i].vm; + struct panthor_as *as =3D ptdev->mmu->as.slots[i].as; =20 - if (vm) - panthor_vm_release_as_locked(vm); + if (as) + panthor_as_release_hw_slot_locked(as); } =20 mutex_unlock(&ptdev->mmu->as.slots_lock); @@ -2031,15 +2044,23 @@ void panthor_mmu_post_reset(struct panthor_device *= ptdev) mutex_unlock(&ptdev->mmu->vm.lock); } =20 -static void panthor_vm_free(struct drm_gpuvm *gpuvm) +static void panthor_vm_release(struct kref *kref) { - struct panthor_vm *vm =3D container_of(gpuvm, struct panthor_vm, base); - struct panthor_device *ptdev =3D vm->ptdev; + struct panthor_vm *vm =3D container_of(kref, struct panthor_vm, refcount); + struct panthor_as *as =3D vm->as; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); =20 + /* Make sure the page table behind this VM doesn't participate in reclaim + * after that point, since we're about to release everything anyway. + */ mutex_lock(&ptdev->base.gem_lru_mutex); - list_del_init(&vm->reclaim.lru_node); + list_del_init(&as->reclaim.lru_node); mutex_unlock(&ptdev->base.gem_lru_mutex); =20 + /* Unmap everything in case some BOs were still mapped. */ + drm_WARN_ON(&ptdev->base, + panthor_vm_unmap_range(vm, as->base.mm_start, as->base.mm_range)); + mutex_lock(&vm->heaps.lock); if (drm_WARN_ON(&ptdev->base, vm->heaps.pool)) panthor_heap_pool_destroy(vm->heaps.pool); @@ -2060,29 +2081,26 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm) drm_sched_entity_destroy(&vm->entity); drm_sched_fini(&vm->sched); =20 - mutex_lock(&vm->op_lock); + mutex_lock(&vm->as->op_lock); mutex_lock(&ptdev->mmu->as.slots_lock); - if (vm->as.id >=3D 0) { + if (as->hw_slot.id >=3D 0) { int cookie; =20 if (drm_dev_enter(&ptdev->base, &cookie)) { - panthor_mmu_as_disable(ptdev, vm->as.id, false); + panthor_mmu_as_disable(ptdev, as->hw_slot.id, false); drm_dev_exit(cookie); } =20 - ptdev->mmu->as.slots[vm->as.id].vm =3D NULL; - clear_bit(vm->as.id, &ptdev->mmu->as.alloc_mask); - list_del(&vm->as.lru_node); + panthor_as_release_hw_slot_locked(as); } mutex_unlock(&ptdev->mmu->as.slots_lock); - mutex_unlock(&vm->op_lock); - - free_io_pgtable_ops(vm->pgtbl_ops); + mutex_unlock(&vm->as->op_lock); =20 if (vm->dummy) drm_gem_object_put(&vm->dummy->base); =20 drm_mm_takedown(&vm->mm); + drm_gpuvm_put(&as->base); kfree(vm); } =20 @@ -2092,7 +2110,8 @@ static void panthor_vm_free(struct drm_gpuvm *gpuvm) */ void panthor_vm_put(struct panthor_vm *vm) { - drm_gpuvm_put(vm ? &vm->base : NULL); + if (vm) + kref_put(&vm->refcount, panthor_vm_release); } =20 /** @@ -2104,7 +2123,7 @@ void panthor_vm_put(struct panthor_vm *vm) struct panthor_vm *panthor_vm_get(struct panthor_vm *vm) { if (vm) - drm_gpuvm_get(&vm->base); + kref_get(&vm->refcount); =20 return vm; } @@ -2125,6 +2144,8 @@ struct panthor_vm *panthor_vm_get(struct panthor_vm *= vm) */ struct panthor_heap_pool *panthor_vm_get_heap_pool(struct panthor_vm *vm, = bool create) { + struct panthor_device *ptdev =3D container_of(vm->as->base.drm, + struct panthor_device, base); struct panthor_heap_pool *pool; =20 mutex_lock(&vm->heaps.lock); @@ -2132,7 +2153,7 @@ struct panthor_heap_pool *panthor_vm_get_heap_pool(st= ruct panthor_vm *vm, bool c if (vm->destroyed) pool =3D ERR_PTR(-EINVAL); else - pool =3D panthor_heap_pool_create(vm->ptdev, vm); + pool =3D panthor_heap_pool_create(ptdev, vm); =20 if (!IS_ERR(pool)) vm->heaps.pool =3D panthor_heap_pool_get(pool); @@ -2167,7 +2188,7 @@ void panthor_vm_heaps_sizes(struct panthor_file *pfil= e, struct drm_memory_stats xa_for_each(&pfile->vms->xa, i, vm) { size_t size =3D panthor_heap_pool_size(vm->heaps.pool); stats->resident +=3D size; - if (vm->as.id >=3D 0) + if (vm->as->hw_slot.id >=3D 0) stats->active +=3D size; } xa_unlock(&pfile->vms->xa); @@ -2215,8 +2236,7 @@ static u64 mair_to_memattr(u64 mair, bool coherent) return memattr; } =20 -static void panthor_vma_link(struct panthor_vm *vm, - struct panthor_vma *vma, +static void panthor_vma_link(struct panthor_vma *vma, struct drm_gpuvm_bo *vm_bo) { struct panthor_gem_object *bo =3D to_panthor_bo(vma->base.gem.obj); @@ -2252,25 +2272,25 @@ panthor_fix_sparse_map_offset(struct drm_gpuva_op_m= ap *op, u32 flags) } =20 static int -panthor_vm_exec_map_op(struct panthor_vm *vm, u32 flags, +panthor_as_exec_map_op(struct panthor_as *as, u32 flags, const struct drm_gpuva_op_map *op) { struct panthor_gem_object *bo =3D to_panthor_bo(op->gem.obj); int prot =3D flags_to_prot(flags); =20 if (flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE) - return panthor_vm_map_sparse(vm, op->va.addr, prot, + return panthor_as_map_sparse(as, op->va.addr, prot, bo->dmap.sgt, op->va.range); =20 - return panthor_vm_map_pages(vm, op->va.addr, prot, bo->dmap.sgt, + return panthor_as_map_pages(as, op->va.addr, prot, bo->dmap.sgt, op->gem.offset, op->va.range); } =20 static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv) { - struct panthor_vm *vm =3D priv; - struct panthor_vm_op_ctx *op_ctx =3D vm->op_ctx; - struct panthor_vma *vma =3D panthor_vm_op_ctx_get_vma(op_ctx); + struct panthor_as *as =3D priv; + struct panthor_as_op_ctx *op_ctx =3D as->op_ctx; + struct panthor_vma *vma =3D panthor_as_op_ctx_get_vma(op_ctx); int ret; =20 if (!vma) @@ -2279,14 +2299,14 @@ static int panthor_gpuva_sm_step_map(struct drm_gpu= va_op *op, void *priv) panthor_vma_init(vma, op_ctx->flags & PANTHOR_VM_MAP_FLAGS); panthor_fix_sparse_map_offset(&op->map, vma->flags); =20 - ret =3D panthor_vm_exec_map_op(vm, vma->flags, &op->map); + ret =3D panthor_as_exec_map_op(as, vma->flags, &op->map); if (ret) { - panthor_vm_op_ctx_return_vma(op_ctx, vma); + panthor_as_op_ctx_return_vma(op_ctx, vma); return ret; } =20 - drm_gpuva_map(&vm->base, &vma->base, &op->map); - panthor_vma_link(vm, vma, op_ctx->map.vm_bo); + drm_gpuva_map(&as->base, &vma->base, &op->map); + panthor_vma_link(vma, op_ctx->map.vm_bo); =20 drm_gpuvm_bo_put_deferred(op_ctx->map.vm_bo); op_ctx->map.vm_bo =3D NULL; @@ -2347,8 +2367,8 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpu= va_op *op, void *priv) { struct panthor_vma *unmap_vma =3D container_of(op->remap.unmap->va, struc= t panthor_vma, base); - struct panthor_vm *vm =3D priv; - struct panthor_vm_op_ctx *op_ctx =3D vm->op_ctx; + struct panthor_as *as =3D priv; + struct panthor_as_op_ctx *op_ctx =3D as->op_ctx; struct panthor_vma *prev_vma =3D NULL, *next_vma =3D NULL; u64 unmap_start, unmap_range; int ret; @@ -2374,8 +2394,8 @@ static int panthor_gpuva_sm_step_remap(struct drm_gpu= va_op *op, * atomicity. panthor_vm_lock_region() bails out early if the new region * is already part of the locked region, so no need to do this check her= e. */ - panthor_vm_lock_region(vm, unmap_start, unmap_range); - panthor_vm_unmap_pages(vm, unmap_start, unmap_range); + panthor_as_lock_region(as, unmap_start, unmap_range); + panthor_as_unmap_pages(as, unmap_start, unmap_range); } =20 if (op->remap.prev) { @@ -2391,12 +2411,12 @@ static int panthor_gpuva_sm_step_remap(struct drm_g= puva_op *op, }; panthor_fix_sparse_map_offset(&map_op, unmap_vma->flags); =20 - ret =3D panthor_vm_exec_map_op(vm, unmap_vma->flags, &map_op); + ret =3D panthor_as_exec_map_op(as, unmap_vma->flags, &map_op); if (ret) return ret; } =20 - prev_vma =3D panthor_vm_op_ctx_get_vma(op_ctx); + prev_vma =3D panthor_as_op_ctx_get_vma(op_ctx); panthor_vma_init(prev_vma, unmap_vma->flags); prev_vma->evicted =3D unmap_vma->evicted; } @@ -2414,12 +2434,12 @@ static int panthor_gpuva_sm_step_remap(struct drm_g= puva_op *op, }; panthor_fix_sparse_map_offset(&map_op, unmap_vma->flags); =20 - ret =3D panthor_vm_exec_map_op(vm, unmap_vma->flags, &map_op); + ret =3D panthor_as_exec_map_op(as, unmap_vma->flags, &map_op); if (ret) return ret; } =20 - next_vma =3D panthor_vm_op_ctx_get_vma(op_ctx); + next_vma =3D panthor_as_op_ctx_get_vma(op_ctx); panthor_vma_init(next_vma, unmap_vma->flags); next_vma->evicted =3D unmap_vma->evicted; } @@ -2434,11 +2454,11 @@ static int panthor_gpuva_sm_step_remap(struct drm_g= puva_op *op, * owned by the old mapping which will be released when this * mapping is destroyed, we need to grab a ref here. */ - panthor_vma_link(vm, prev_vma, op->remap.unmap->va->vm_bo); + panthor_vma_link(prev_vma, op->remap.unmap->va->vm_bo); } =20 if (next_vma) { - panthor_vma_link(vm, next_vma, op->remap.unmap->va->vm_bo); + panthor_vma_link(next_vma, op->remap.unmap->va->vm_bo); } =20 panthor_vma_unlink(unmap_vma); @@ -2449,10 +2469,10 @@ static int panthor_gpuva_sm_step_unmap(struct drm_g= puva_op *op, void *priv) { struct panthor_vma *unmap_vma =3D container_of(op->unmap.va, struct panth= or_vma, base); - struct panthor_vm *vm =3D priv; + struct panthor_as *as =3D priv; =20 if (!unmap_vma->evicted) { - panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr, + panthor_as_unmap_pages(as, unmap_vma->base.va.addr, unmap_vma->base.va.range); } =20 @@ -2464,7 +2484,7 @@ static int panthor_gpuva_sm_step_unmap(struct drm_gpu= va_op *op, void panthor_vm_update_bo_reclaim_lru_locked(struct panthor_gem_object *bo) { struct panthor_device *ptdev =3D container_of(bo->base.dev, struct pantho= r_device, base); - struct panthor_vm *vm =3D NULL; + struct panthor_as *as =3D NULL; struct drm_gpuvm_bo *vm_bo; =20 dma_resv_assert_held(bo->base.resv); @@ -2477,13 +2497,13 @@ void panthor_vm_update_bo_reclaim_lru_locked(struct= panthor_gem_object *bo) /* We're only supposed to have one non-evicted vm_bo in the list if we g= et * there. */ - drm_WARN_ON(&ptdev->base, vm); - vm =3D container_of(vm_bo->vm, struct panthor_vm, base); + drm_WARN_ON(&ptdev->base, as); + as =3D container_of(vm_bo->vm, struct panthor_as, base); =20 mutex_lock(&ptdev->base.gem_lru_mutex); - drm_gem_lru_move_tail_locked(&vm->reclaim.lru, &bo->base); - if (list_empty(&vm->reclaim.lru_node)) - list_move(&vm->reclaim.lru_node, &ptdev->reclaim.vms); + drm_gem_lru_move_tail_locked(&as->reclaim.lru, &bo->base); + if (list_empty(&as->reclaim.lru_node)) + list_move(&as->reclaim.lru_node, &ptdev->reclaim.vms); mutex_unlock(&ptdev->base.gem_lru_mutex); } } @@ -2494,10 +2514,11 @@ int panthor_vm_evict_bo_mappings_locked(struct pant= hor_gem_object *bo) int ret =3D 0; =20 drm_gem_for_each_gpuvm_bo(vm_bo, &bo->base) { - struct panthor_vm *vm =3D container_of(vm_bo->vm, struct panthor_vm, bas= e); + struct panthor_as *as =3D container_of(vm_bo->vm, + struct panthor_as, base); struct drm_gpuva *va; =20 - if (!mutex_trylock(&vm->op_lock)) + if (!mutex_trylock(&as->op_lock)) return -EDEADLK; =20 /* It can be that the vm_bo was already evicted but a new @@ -2526,16 +2547,16 @@ int panthor_vm_evict_bo_mappings_locked(struct pant= hor_gem_object *bo) * will be validated, causing all its evicted VMAs to be repopulated * before the job runs. So no GPU fault expected. */ - ret =3D panthor_vm_lock_region(vm, va->va.addr, va->va.range); + ret =3D panthor_as_lock_region(as, va->va.addr, va->va.range); if (ret) break; =20 - panthor_vm_unmap_pages(vm, va->va.addr, va->va.range); - panthor_vm_unlock_region(vm); + panthor_as_unmap_pages(as, va->va.addr, va->va.range); + panthor_as_unlock_region(as); vma->evicted =3D true; } =20 - mutex_unlock(&vm->op_lock); + mutex_unlock(&as->op_lock); =20 if (ret) break; @@ -2545,14 +2566,14 @@ int panthor_vm_evict_bo_mappings_locked(struct pant= hor_gem_object *bo) } =20 static struct panthor_vma *select_evicted_vma(struct drm_gpuvm_bo *vm_bo, - struct panthor_vm_op_ctx *op_ctx) + struct panthor_as_op_ctx *op_ctx) { - struct panthor_vm *vm =3D container_of(vm_bo->vm, struct panthor_vm, base= ); + struct panthor_as *as =3D container_of(vm_bo->vm, struct panthor_as, base= ); struct panthor_vma *first_evicted_vma =3D NULL; struct drm_gpuva *va; =20 /* Take op_lock to protect against va insertion/removal. */ - mutex_lock(&vm->op_lock); + mutex_lock(&as->op_lock); drm_gpuvm_bo_for_each_va(va, vm_bo) { struct panthor_vma *vma =3D container_of(va, struct panthor_vma, base); =20 @@ -2563,22 +2584,22 @@ static struct panthor_vma *select_evicted_vma(struc= t drm_gpuvm_bo *vm_bo, break; } } - mutex_unlock(&vm->op_lock); + mutex_unlock(&as->op_lock); =20 return first_evicted_vma; } =20 static int remap_evicted_vma(struct drm_gpuvm_bo *vm_bo, struct panthor_vma *evicted_vma, - struct panthor_vm_op_ctx *op_ctx) + struct panthor_as_op_ctx *op_ctx) { - struct panthor_vm *vm =3D container_of(vm_bo->vm, struct panthor_vm, base= ); + struct panthor_as *as =3D container_of(vm_bo->vm, struct panthor_as, base= ); struct panthor_gem_object *bo =3D to_panthor_bo(vm_bo->obj); struct drm_gpuva *va; bool found =3D false; int ret; =20 - ret =3D panthor_vm_op_ctx_prealloc_pts(op_ctx); + ret =3D panthor_as_op_ctx_prealloc_pts(op_ctx); if (ret) goto out_cleanup; =20 @@ -2587,7 +2608,7 @@ static int remap_evicted_vma(struct drm_gpuvm_bo *vm_= bo, * to release it so we can allocate PTs, because this very same lock * is taken in a DMA-signalling path. */ - mutex_lock(&vm->op_lock); + mutex_lock(&as->op_lock); drm_gpuvm_bo_for_each_va(va, vm_bo) { struct panthor_vma *vma =3D container_of(va, struct panthor_vma, base); =20 @@ -2607,8 +2628,8 @@ static int remap_evicted_vma(struct drm_gpuvm_bo *vm_= bo, } =20 if (found) { - vm->op_ctx =3D op_ctx; - ret =3D panthor_vm_lock_region(vm, evicted_vma->base.va.addr, + as->op_ctx =3D op_ctx; + ret =3D panthor_as_lock_region(as, evicted_vma->base.va.addr, evicted_vma->base.va.range); if (!ret) { struct drm_gpuva_op_map map_op =3D { @@ -2617,34 +2638,37 @@ static int remap_evicted_vma(struct drm_gpuvm_bo *v= m_bo, .gem.obj =3D &bo->base, .gem.offset =3D evicted_vma->base.gem.offset, }; - if (evicted_vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE) - drm_WARN_ON_ONCE(&vm->ptdev->base, map_op.gem.offset !=3D - (map_op.va.addr & (SZ_2M - 1))); + if (evicted_vma->flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE) { + u64 expected_offset =3D map_op.va.addr & (SZ_2M - 1); =20 - ret =3D panthor_vm_exec_map_op(vm, evicted_vma->flags, &map_op); + drm_WARN_ON_ONCE(as->base.drm, + map_op.gem.offset !=3D expected_offset); + } + + ret =3D panthor_as_exec_map_op(as, evicted_vma->flags, &map_op); if (!ret) evicted_vma->evicted =3D false; =20 - panthor_vm_unlock_region(vm); + panthor_as_unlock_region(as); } =20 - vm->op_ctx =3D NULL; + as->op_ctx =3D NULL; } =20 - mutex_unlock(&vm->op_lock); + mutex_unlock(&as->op_lock); =20 out_cleanup: - panthor_vm_cleanup_op_ctx(op_ctx, vm); + panthor_as_cleanup_op_ctx(op_ctx, as); return ret; } =20 static int panthor_vm_restore_vmas(struct drm_gpuvm_bo *vm_bo) { - struct panthor_vm *vm =3D container_of(vm_bo->vm, struct panthor_vm, base= ); + struct panthor_as *as =3D container_of(vm_bo->vm, struct panthor_as, base= ); struct panthor_gem_object *bo =3D to_panthor_bo(vm_bo->obj); - struct panthor_vm_op_ctx op_ctx; + struct panthor_as_op_ctx op_ctx; =20 - if (drm_WARN_ON_ONCE(&vm->ptdev->base, !bo->dmap.sgt)) + if (drm_WARN_ON_ONCE(as->base.drm, !bo->dmap.sgt)) return -EINVAL; =20 for (struct panthor_vma *vma =3D select_evicted_vma(vm_bo, &op_ctx); @@ -2680,8 +2704,19 @@ static int panthor_vm_bo_validate(struct drm_gpuvm_b= o *vm_bo, return 0; } =20 +static void panthor_as_free(struct drm_gpuvm *gpuvm) +{ + struct panthor_as *as =3D container_of(gpuvm, struct panthor_as, base); + + if (as->pt.ops) + free_io_pgtable_ops(as->pt.ops); + + mutex_destroy(&as->op_lock); + kfree(as); +} + static const struct drm_gpuvm_ops panthor_gpuvm_ops =3D { - .vm_free =3D panthor_vm_free, + .vm_free =3D panthor_as_free, .vm_bo_free =3D panthor_vm_bo_free, .sm_step_map =3D panthor_gpuva_sm_step_map, .sm_step_remap =3D panthor_gpuva_sm_step_remap, @@ -2697,7 +2732,7 @@ static const struct drm_gpuvm_ops panthor_gpuvm_ops = =3D { */ struct dma_resv *panthor_vm_resv(struct panthor_vm *vm) { - return drm_gpuvm_resv(&vm->base); + return drm_gpuvm_resv(&vm->as->base); } =20 struct drm_gem_object *panthor_vm_root_gem(struct panthor_vm *vm) @@ -2705,12 +2740,12 @@ struct drm_gem_object *panthor_vm_root_gem(struct p= anthor_vm *vm) if (!vm) return NULL; =20 - return vm->base.r_obj; + return vm->as->base.r_obj; } =20 -static int -panthor_vm_exec_op(struct panthor_vm *vm, struct panthor_vm_op_ctx *op, - bool flag_vm_unusable_on_failure) +static int panthor_as_exec_op(struct panthor_as *as, + struct panthor_as_op_ctx *op, + bool flag_vm_unusable_on_failure) { u32 op_type =3D op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK; int ret; @@ -2718,10 +2753,10 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct pa= nthor_vm_op_ctx *op, if (op_type =3D=3D DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY) return 0; =20 - mutex_lock(&vm->op_lock); - vm->op_ctx =3D op; + mutex_lock(&as->op_lock); + as->op_ctx =3D op; =20 - ret =3D panthor_vm_lock_region(vm, op->va.addr, op->va.range); + ret =3D panthor_as_lock_region(as, op->va.addr, op->va.range); if (ret) goto out; =20 @@ -2734,17 +2769,17 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct pa= nthor_vm_op_ctx *op, .map.gem.offset =3D op->map.bo_offset, }; =20 - if (vm->unusable) { + if (as->unusable) { ret =3D -EINVAL; break; } =20 - ret =3D drm_gpuvm_sm_map(&vm->base, vm, &map_req); + ret =3D drm_gpuvm_sm_map(&as->base, as, &map_req); break; } =20 case DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP: - ret =3D drm_gpuvm_sm_unmap(&vm->base, vm, op->va.addr, op->va.range); + ret =3D drm_gpuvm_sm_unmap(&as->base, as, op->va.addr, op->va.range); break; =20 default: @@ -2752,14 +2787,14 @@ panthor_vm_exec_op(struct panthor_vm *vm, struct pa= nthor_vm_op_ctx *op, break; } =20 - panthor_vm_unlock_region(vm); + panthor_as_unlock_region(as); =20 out: if (ret && flag_vm_unusable_on_failure) - panthor_vm_declare_unusable(vm); + panthor_as_declare_unusable(as); =20 - vm->op_ctx =3D NULL; - mutex_unlock(&vm->op_lock); + as->op_ctx =3D NULL; + mutex_unlock(&as->op_lock); =20 return ret; } @@ -2777,7 +2812,7 @@ panthor_vm_bind_run_job(struct drm_sched_job *sched_j= ob) * to be destroyed and recreated. */ cookie =3D dma_fence_begin_signalling(); - ret =3D panthor_vm_exec_op(job->vm, &job->ctx, true); + ret =3D panthor_as_exec_op(job->vm->as, &job->ctx, true); dma_fence_end_signalling(cookie); =20 return ret ? ERR_PTR(ret) : NULL; @@ -2790,7 +2825,7 @@ static void panthor_vm_bind_job_release(struct kref *= kref) if (job->base.s_fence) drm_sched_job_cleanup(&job->base); =20 - panthor_vm_cleanup_op_ctx(&job->ctx, job->vm); + panthor_as_cleanup_op_ctx(&job->ctx, job->vm->as); panthor_vm_put(job->vm); kfree(job); } @@ -2835,6 +2870,62 @@ static const struct drm_sched_backend_ops panthor_vm= _bind_ops =3D { .timedout_job =3D panthor_vm_bind_timedout_job, }; =20 +static struct panthor_as * +panthor_as_create(struct panthor_device *ptdev, const char *name, + u64 min_va, u64 va_range) +{ + struct io_pgtable_cfg as_cfg =3D { + .pgsize_bitmap =3D ptdev->mmu_info.page_size_bitmap, + .ias =3D GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features), + .oas =3D GPU_MMU_FEATURES_PA_BITS(ptdev->gpu_info.mmu_features), + .coherent_walk =3D ptdev->coherent, + .tlb =3D &mmu_tlb_ops, + .iommu_dev =3D drm_dev_dma_dev(&ptdev->base), + .alloc =3D alloc_pt, + .free =3D free_pt, + }; + struct drm_gem_object *dummy_gem; + struct panthor_as *as; + u64 mair; + + /* We allocate a dummy GEM for the VM. */ + dummy_gem =3D drm_gpuvm_resv_object_alloc(&ptdev->base); + if (!dummy_gem) + return ERR_PTR(-ENOMEM); + + as =3D kzalloc_obj(*as); + if (!as) { + drm_gem_object_put(dummy_gem); + return ERR_PTR(-ENOMEM); + } + + mutex_init(&as->op_lock); + drm_gem_lru_init(&as->reclaim.lru); + INIT_LIST_HEAD(&as->reclaim.lru_node); + INIT_LIST_HEAD(&as->hw_slot.lru_node); + as->hw_slot.id =3D -1; + refcount_set(&as->active_cnt, 0); + + /* We intentionally leave the reserved range to zero, because we want ker= nel VMAs + * to be handled the same way user VMAs are. + */ + drm_gpuvm_init(&as->base, name, + DRM_GPUVM_RESV_PROTECTED | DRM_GPUVM_IMMEDIATE_MODE, + &ptdev->base, dummy_gem, min_va, va_range, 0, 0, + &panthor_gpuvm_ops); + drm_gem_object_put(dummy_gem); + + as->pt.ops =3D alloc_io_pgtable_ops(ARM_64_LPAE_S1, &as_cfg, as); + if (!as->pt.ops) { + drm_gpuvm_put(&as->base); + return ERR_PTR(-EINVAL); + } + + mair =3D io_pgtable_ops_to_pgtable(as->pt.ops)->cfg.arm_lpae_s1_cfg.mair; + as->memattr =3D mair_to_memattr(mair, ptdev->coherent); + return as; +} + /** * panthor_vm_create() - Create a VM * @ptdev: Device. @@ -2852,9 +2943,8 @@ panthor_vm_create(struct panthor_device *ptdev, bool = for_mcu, u64 auto_kernel_va_start, u64 auto_kernel_va_size) { u32 va_bits =3D GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features); - u32 pa_bits =3D GPU_MMU_FEATURES_PA_BITS(ptdev->gpu_info.mmu_features); + const char *name =3D for_mcu ? "panthor-MCU-VM" : "panthor-GPU-VM"; u64 full_va_range =3D 1ull << va_bits; - struct drm_gem_object *dummy_gem; struct drm_gpu_scheduler *sched; const struct drm_sched_init_args sched_args =3D { .ops =3D &panthor_vm_bind_ops, @@ -2865,27 +2955,11 @@ panthor_vm_create(struct panthor_device *ptdev, boo= l for_mcu, .name =3D "panthor-vm-bind", .dev =3D ptdev->base.dev, }; - struct io_pgtable_cfg pgtbl_cfg; - u64 mair, min_va, va_range; + struct panthor_as *as; struct panthor_vm *vm; + u64 min_va, va_range; int ret; =20 - vm =3D kzalloc_obj(*vm); - if (!vm) - return ERR_PTR(-ENOMEM); - - /* We allocate a dummy GEM for the VM. */ - dummy_gem =3D drm_gpuvm_resv_object_alloc(&ptdev->base); - if (!dummy_gem) { - ret =3D -ENOMEM; - goto err_free_vm; - } - - mutex_init(&vm->heaps.lock); - vm->for_mcu =3D for_mcu; - vm->ptdev =3D ptdev; - mutex_init(&vm->op_lock); - if (for_mcu) { /* CSF MCU is a cortex M7, and can only address 4G */ min_va =3D 0; @@ -2895,49 +2969,35 @@ panthor_vm_create(struct panthor_device *ptdev, boo= l for_mcu, va_range =3D full_va_range; } =20 + as =3D panthor_as_create(ptdev, name, min_va, va_range); + if (IS_ERR(as)) + return ERR_CAST(as); + + vm =3D kzalloc_obj(*vm); + if (!vm) { + ret =3D -ENOMEM; + goto err_put_as; + } + vm->user_va_range =3D kernel_va_start; + vm->as =3D as; + mutex_init(&vm->heaps.lock); + vm->for_mcu =3D for_mcu; =20 mutex_init(&vm->mm_lock); drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size); vm->kernel_auto_va.start =3D auto_kernel_va_start; vm->kernel_auto_va.end =3D vm->kernel_auto_va.start + auto_kernel_va_size= - 1; =20 - drm_gem_lru_init(&vm->reclaim.lru); - INIT_LIST_HEAD(&vm->reclaim.lru_node); - INIT_LIST_HEAD(&vm->node); - INIT_LIST_HEAD(&vm->as.lru_node); - vm->as.id =3D -1; - refcount_set(&vm->as.active_cnt, 0); - - pgtbl_cfg =3D (struct io_pgtable_cfg) { - .pgsize_bitmap =3D ptdev->mmu_info.page_size_bitmap, - .ias =3D va_bits, - .oas =3D pa_bits, - .coherent_walk =3D ptdev->coherent, - .tlb =3D &mmu_tlb_ops, - .iommu_dev =3D ptdev->base.dev, - .alloc =3D alloc_pt, - .free =3D free_pt, - }; - - vm->pgtbl_ops =3D alloc_io_pgtable_ops(ARM_64_LPAE_S1, &pgtbl_cfg, vm); - if (!vm->pgtbl_ops) { - ret =3D -EINVAL; - goto err_mm_takedown; - } - ret =3D drm_sched_init(&vm->sched, &sched_args); if (ret) - goto err_free_io_pgtable; + goto err_free_vm; =20 sched =3D &vm->sched; ret =3D drm_sched_entity_init(&vm->entity, 0, &sched, 1, NULL); if (ret) goto err_sched_fini; =20 - mair =3D io_pgtable_ops_to_pgtable(vm->pgtbl_ops)->cfg.arm_lpae_s1_cfg.ma= ir; - vm->memattr =3D mair_to_memattr(mair, ptdev->coherent); - mutex_lock(&ptdev->mmu->vm.lock); list_add_tail(&vm->node, &ptdev->mmu->vm.list); =20 @@ -2946,28 +3006,20 @@ panthor_vm_create(struct panthor_device *ptdev, boo= l for_mcu, panthor_vm_stop(vm); mutex_unlock(&ptdev->mmu->vm.lock); =20 - /* We intentionally leave the reserved range to zero, because we want ker= nel VMAs - * to be handled the same way user VMAs are. - */ - drm_gpuvm_init(&vm->base, for_mcu ? "panthor-MCU-VM" : "panthor-GPU-VM", - DRM_GPUVM_RESV_PROTECTED | DRM_GPUVM_IMMEDIATE_MODE, - &ptdev->base, dummy_gem, min_va, va_range, 0, 0, - &panthor_gpuvm_ops); - drm_gem_object_put(dummy_gem); + kref_init(&vm->refcount); return vm; =20 err_sched_fini: drm_sched_fini(&vm->sched); =20 -err_free_io_pgtable: - free_io_pgtable_ops(vm->pgtbl_ops); - -err_mm_takedown: - drm_mm_takedown(&vm->mm); - drm_gem_object_put(dummy_gem); - err_free_vm: + drm_mm_takedown(&vm->mm); + mutex_destroy(&vm->mm_lock); + mutex_destroy(&vm->heaps.lock); kfree(vm); + +err_put_as: + drm_gpuvm_put(&as->base); return ERR_PTR(ret); } =20 @@ -2975,7 +3027,7 @@ static int panthor_vm_bind_prepare_op_ctx(struct drm_file *file, struct panthor_vm *vm, const struct drm_panthor_vm_bind_op *op, - struct panthor_vm_op_ctx *op_ctx) + struct panthor_as_op_ctx *op_ctx) { ssize_t vm_pgsz =3D panthor_vm_page_size(vm); struct drm_gem_object *gem; @@ -2998,7 +3050,7 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file, drm_gem_object_get(&vm->dummy->base); } =20 - ret =3D panthor_vm_prepare_map_op_ctx(op_ctx, vm, + ret =3D panthor_as_prepare_map_op_ctx(op_ctx, vm->as, gem ? to_panthor_bo(gem) : NULL, op); drm_gem_object_put(gem); @@ -3011,7 +3063,7 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file, if (op->bo_handle || op->bo_offset) return -EINVAL; =20 - return panthor_vm_prepare_unmap_op_ctx(op_ctx, vm, op->va, op->size); + return panthor_as_prepare_unmap_op_ctx(op_ctx, vm->as, op->va, op->size); =20 case DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY: if (op->flags & ~DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) @@ -3026,7 +3078,7 @@ panthor_vm_bind_prepare_op_ctx(struct drm_file *file, if (!op->syncs.count) return -EINVAL; =20 - panthor_vm_prepare_sync_only_op_ctx(op_ctx); + panthor_as_prepare_sync_only_op_ctx(op_ctx); return 0; =20 default: @@ -3061,7 +3113,7 @@ panthor_vm_bind_job_create(struct drm_file *file, if (!vm) return ERR_PTR(-EINVAL); =20 - if (vm->destroyed || vm->unusable) + if (vm->destroyed || vm->as->unusable) return ERR_PTR(-EINVAL); =20 job =3D kzalloc_obj(*job); @@ -3107,7 +3159,7 @@ int panthor_vm_bind_job_prepare_resvs(struct drm_exec= *exec, int ret; =20 /* Acquire the VM lock an reserve a slot for this VM bind job. */ - ret =3D drm_gpuvm_prepare_vm(&job->vm->base, exec, 1); + ret =3D drm_gpuvm_prepare_vm(&job->vm->as->base, exec, 1); if (ret) return ret; =20 @@ -3132,7 +3184,7 @@ void panthor_vm_bind_job_update_resvs(struct drm_exec= *exec, struct panthor_vm_bind_job *job =3D container_of(sched_job, struct pantho= r_vm_bind_job, base); =20 /* Explicit sync =3D> we just register our job finished fence as bookkeep= . */ - drm_gpuvm_resv_add_fence(&job->vm->base, exec, + drm_gpuvm_resv_add_fence(&job->vm->as->base, exec, &sched_job->s_fence->finished, DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_BOOKKEEP); @@ -3143,7 +3195,7 @@ void panthor_vm_update_resvs(struct panthor_vm *vm, s= truct drm_exec *exec, enum dma_resv_usage private_usage, enum dma_resv_usage extobj_usage) { - drm_gpuvm_resv_add_fence(&vm->base, exec, fence, private_usage, extobj_us= age); + drm_gpuvm_resv_add_fence(&vm->as->base, exec, fence, private_usage, extob= j_usage); } =20 /** @@ -3158,7 +3210,7 @@ int panthor_vm_bind_exec_sync_op(struct drm_file *fil= e, struct panthor_vm *vm, struct drm_panthor_vm_bind_op *op) { - struct panthor_vm_op_ctx op_ctx; + struct panthor_as_op_ctx op_ctx; int ret; =20 /* No sync objects allowed on synchronous operations. */ @@ -3172,8 +3224,8 @@ int panthor_vm_bind_exec_sync_op(struct drm_file *fil= e, if (ret) return ret; =20 - ret =3D panthor_vm_exec_op(vm, &op_ctx, false); - panthor_vm_cleanup_op_ctx(&op_ctx, vm); + ret =3D panthor_as_exec_op(vm->as, &op_ctx, false); + panthor_as_cleanup_op_ctx(&op_ctx, vm->as); =20 return ret; } @@ -3202,18 +3254,18 @@ int panthor_vm_map_bo_range(struct panthor_vm *vm, = struct panthor_gem_object *bo .va =3D va, .flags =3D flags, }; - struct panthor_vm_op_ctx op_ctx; + struct panthor_as_op_ctx op_ctx; int ret; =20 - if (drm_WARN_ON(&vm->ptdev->base, flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPAR= SE)) + if (drm_WARN_ON(vm->as->base.drm, flags & DRM_PANTHOR_VM_BIND_OP_MAP_SPAR= SE)) return -EINVAL; =20 - ret =3D panthor_vm_prepare_map_op_ctx(&op_ctx, vm, bo, &op); + ret =3D panthor_as_prepare_map_op_ctx(&op_ctx, vm->as, bo, &op); if (ret) return ret; =20 - ret =3D panthor_vm_exec_op(vm, &op_ctx, false); - panthor_vm_cleanup_op_ctx(&op_ctx, vm); + ret =3D panthor_as_exec_op(vm->as, &op_ctx, false); + panthor_as_cleanup_op_ctx(&op_ctx, vm->as); =20 return ret; } @@ -3231,15 +3283,15 @@ int panthor_vm_map_bo_range(struct panthor_vm *vm, = struct panthor_gem_object *bo */ int panthor_vm_unmap_range(struct panthor_vm *vm, u64 va, u64 size) { - struct panthor_vm_op_ctx op_ctx; + struct panthor_as_op_ctx op_ctx; int ret; =20 - ret =3D panthor_vm_prepare_unmap_op_ctx(&op_ctx, vm, va, size); + ret =3D panthor_as_prepare_unmap_op_ctx(&op_ctx, vm->as, va, size); if (ret) return ret; =20 - ret =3D panthor_vm_exec_op(vm, &op_ctx, false); - panthor_vm_cleanup_op_ctx(&op_ctx, vm); + ret =3D panthor_as_exec_op(vm->as, &op_ctx, false); + panthor_as_cleanup_op_ctx(&op_ctx, vm->as); =20 return ret; } @@ -3263,15 +3315,15 @@ int panthor_vm_prepare_mapped_bos_resvs(struct drm_= exec *exec, struct panthor_vm int ret; =20 /* Acquire the VM lock and reserve a slot for this GPU job. */ - ret =3D drm_gpuvm_prepare_vm(&vm->base, exec, slot_count); + ret =3D drm_gpuvm_prepare_vm(&vm->as->base, exec, slot_count); if (ret) return ret; =20 - ret =3D drm_gpuvm_prepare_objects(&vm->base, exec, slot_count); + ret =3D drm_gpuvm_prepare_objects(&vm->as->base, exec, slot_count); if (ret) return ret; =20 - return drm_gpuvm_validate(&vm->base, exec); + return drm_gpuvm_validate(&vm->as->base, exec); } =20 unsigned long @@ -3288,21 +3340,21 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device = *ptdev, list_splice_init(&ptdev->reclaim.vms, &vms); =20 while (freed < nr_to_scan) { - struct panthor_vm *vm; + struct panthor_as *as; =20 - vm =3D list_first_entry_or_null(&vms, typeof(*vm), + as =3D list_first_entry_or_null(&vms, typeof(*as), reclaim.lru_node); - if (!vm) + if (!as) break; =20 - if (!kref_get_unless_zero(&vm->base.kref)) { - list_del_init(&vm->reclaim.lru_node); + if (!kref_get_unless_zero(&as->base.kref)) { + list_del_init(&as->reclaim.lru_node); continue; } =20 mutex_unlock(&ptdev->base.gem_lru_mutex); =20 - freed +=3D drm_gem_lru_scan(&ptdev->base, &vm->reclaim.lru, + freed +=3D drm_gem_lru_scan(&ptdev->base, &as->reclaim.lru, nr_to_scan - freed, remaining, shrink, NULL); =20 @@ -3311,20 +3363,20 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device = *ptdev, /* If the VM is still in the temporary list, remove it so we * can proceed with the next VM. */ - if (vm =3D=3D list_first_entry_or_null(&vms, typeof(*vm), reclaim.lru_no= de)) { - list_del_init(&vm->reclaim.lru_node); + if (as =3D=3D list_first_entry_or_null(&vms, typeof(*as), reclaim.lru_no= de)) { + list_del_init(&as->reclaim.lru_node); =20 /* Keep the VM around if there are still things to * reclaim, so we can preserve the LRU order when * re-inserting in ptdev->reclaim.vms at the end. */ - if (vm->reclaim.lru.count > 0) - list_add_tail(&vm->reclaim.lru_node, &remaining_vms); + if (as->reclaim.lru.count > 0) + list_add_tail(&as->reclaim.lru_node, &remaining_vms); } =20 mutex_unlock(&ptdev->base.gem_lru_mutex); =20 - panthor_vm_put(vm); + drm_gpuvm_put(&as->base); =20 mutex_lock(&ptdev->base.gem_lru_mutex); } @@ -3356,12 +3408,12 @@ void panthor_mmu_unplug(struct panthor_device *ptde= v) =20 mutex_lock(&ptdev->mmu->as.slots_lock); for (u32 i =3D 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { - struct panthor_vm *vm =3D ptdev->mmu->as.slots[i].vm; + struct panthor_as *as =3D ptdev->mmu->as.slots[i].as; =20 - if (vm) { + if (as) { drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i, false)); - panthor_vm_release_as_locked(vm); + panthor_as_release_hw_slot_locked(as); } } mutex_unlock(&ptdev->mmu->as.slots_lock); @@ -3445,9 +3497,9 @@ static int show_vm_gpuvas(struct panthor_vm *vm, stru= ct seq_file *m) { int ret; =20 - mutex_lock(&vm->op_lock); - ret =3D drm_debugfs_gpuva_info(m, &vm->base); - mutex_unlock(&vm->op_lock); + mutex_lock(&vm->as->op_lock); + ret =3D drm_debugfs_gpuva_info(m, &vm->as->base); + mutex_unlock(&vm->as->op_lock); =20 return ret; } --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 819234562A3 for ; Tue, 4 Aug 2026 10:10:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838208; cv=none; b=AJIG58TJHY34XSrLUXmDAOwBjWFe8M05MlAFhU+5OzXNJBsoF+mhBSUrwDo5j+KY/fftTbSJAZ/co+EjMrS2RYgg+rhXCKwTfEGke9O4subp28G7E0dSB0OtbTTdwO/V3NgMcoK6Gdv7Xh8Ati+DvDxy5XKnW1aZGsNEYWpwDVw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838208; c=relaxed/simple; bh=nGwY/4G2VwI8VrkXPuOYB5yY2bEnLxfjdzwnjauwB4k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=plrUl1cpFFxPPZtnYZKzIEANtedhTbPpjYQ2ArLBFyaM4HFmRDsiuIhjQlxxtPIjlZ0bplh/RGBGWIV1zOFTC1025em8z4zv86yjbMMdROtYXg2/QLEyw5yeIBfK3vQZkh7L8yU6VhLDtfDqvmcx/8O4P3NO1ozFGd0XsBHv7zo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=GpT+u6Eg; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="GpT+u6Eg" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838198; bh=nGwY/4G2VwI8VrkXPuOYB5yY2bEnLxfjdzwnjauwB4k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=GpT+u6EgojHF1JRC8wqYHT/0gkVN0pYyNyY0s+9Ch+jWRs/WoF7z+DDwufJEbEcUU KzwEgKdRd5Via7aOwKx8Od12u/yKObxa9Rgsu4kMI74DylF4HW7jHMoAlZZ8HwkpN3 Bd3sEvqNedbAlgGv4fk743dIPLoX0RXwbov0OeQTPyhNGZdIQ1dQl2E/1ExzBOJPw0 7QxLaq7wkuoydXcRMCWk0Nbj8X5jg9WfjzwS9opDBfj78ycZc1Y44hsXgkPZ26uzrX P7hNmXQRdIJQXa+E5wLBN+GacKBGcQew+X6yabFaIprDkPk+WSeQifDx9t5dmJs/4t 62AtWxDLhqUWQ== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 2492F17E10BE; Tue, 04 Aug 2026 12:09:58 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:46 +0200 Subject: [PATCH 07/12] drm/panthor: Add fine-grained restrictions on VMs Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-7-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=8230; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=nGwY/4G2VwI8VrkXPuOYB5yY2bEnLxfjdzwnjauwB4k=; b=3+j0u9C7qfUPv5XKgXd5/KnG3tGmW15ecqDIUtWrD6RyjnwQgWbQC5t/2vTesUj4Jil8REU9m LxiwQW+adRHBqhj46z2Wo6gRiLFh2xh4GkhNY2+GiKo4KSuHhjL74gD X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= We currently restrict what a VM is allowed to do based on two states: panthor_vm::destroyed and panthor_vm_pgtable::unusable, but we'll soon need a no-unmap restriction to fix the unplug logic. Instead of adding a third boolean that would reflect this new limitation, let's overhaul the current restriction logic by adding separate restriction flags representing the operations we want to prevent (map, unmap and use). Map and use restrictions are set everywhere we were previously calling panthor_vm_pgtable_declare_unusable() or setting ::destroyed to true, since that's what those two flags were preventing. We also add restriction checks in panthor_vm_pgtable_prepare_[un]map_op_ctx() and panthor_vm_pgtable_exec_op() and drop the ones we had in panthor_vm_bind_job_create() since they are redundant. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 101 ++++++++++++++++++++++++------= ---- 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index 2d462813a711..9a9025b02e28 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -215,6 +215,25 @@ struct panthor_as_op_ctx { } map; }; =20 +/** + * enum panthor_as_restriction - List of restrictions that can apply to an= AS. + * + * An AS always starts unrestricted, but based on the faults or device sta= te + * changes, restrictions can be added over time. Restrictions can't be rem= oved + * though. Once a VM is restricted, a new one must be created to lift the + * restrictions. + */ +enum panthor_as_restriction { + /** @PANTHOR_AS_FORBID_MAP: The AS can't map new buffers. */ + PANTHOR_AS_FORBID_MAP =3D BIT(0), + + /** @PANTHOR_AS_FORBID_UNMAP: The AS can't remove existing mappings. */ + PANTHOR_AS_FORBID_UNMAP =3D BIT(1), + + /** @PANTHOR_AS_FORBID_USE: The AS can't become active again. */ + PANTHOR_AS_FORBID_USE =3D BIT(2), +}; + /** * struct panthor_as - Used to managed a GPU address space. */ @@ -295,6 +314,9 @@ struct panthor_as { */ bool unusable; =20 + /** @restrictions: Bitmask of panthor_as_restriction flags. */ + atomic_t restrictions; + /** * @unhandled_fault: Unhandled fault happened. * @@ -411,13 +433,6 @@ struct panthor_vm { /** @for_mcu: True if this is the MCU VM. */ bool for_mcu; =20 - /** - * @destroyed: True if the VM was destroyed. - * - * No further bind requests should be queued to a destroyed VM. - */ - bool destroyed; - /** * @dummy: Dummy object used for sparse mappings. * @@ -693,7 +708,9 @@ bool panthor_vm_has_unhandled_faults(struct panthor_vm = *vm) */ bool panthor_vm_is_unusable(struct panthor_vm *vm) { - return vm->as->unusable; + return (atomic_read(&vm->as->restrictions) & + (PANTHOR_AS_FORBID_USE | PANTHOR_AS_FORBID_MAP | + PANTHOR_AS_FORBID_UNMAP)); } =20 static void panthor_as_release_hw_slot_locked(struct panthor_as *as) @@ -752,6 +769,11 @@ int panthor_vm_active(struct panthor_vm *vm) mutex_lock(&as->op_lock); mutex_lock(&ptdev->mmu->as.slots_lock); =20 + if (atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_USE) { + ret =3D -EINVAL; + goto out_unlock; + } + if (refcount_inc_not_zero(&as->active_cnt)) goto out_unlock; =20 @@ -920,21 +942,27 @@ static size_t get_pgsize(u64 addr, size_t size, size_= t *count) return SZ_2M; } =20 -static void panthor_as_declare_unusable(struct panthor_as *as) +static void panthor_as_restrict_usage_locked(struct panthor_as *as, + u32 new_restrictions) { struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); int cookie; =20 - if (as->unusable) - return; - - as->unusable =3D true; - mutex_lock(&ptdev->mmu->as.slots_lock); - if (as->hw_slot.id >=3D 0 && drm_dev_enter(&ptdev->base, &cookie)) { - panthor_mmu_as_disable(ptdev, as->hw_slot.id, false); - drm_dev_exit(cookie); + if (new_restrictions & PANTHOR_AS_FORBID_USE) { + guard(mutex)(&ptdev->mmu->as.slots_lock); + if (as->hw_slot.id >=3D 0 && drm_dev_enter(&ptdev->base, &cookie)) { + /* Try to disable the AS. If as_disable() passed, this should cause + * a fault on the next memory access. If it failed, a reset is + * scheduled to recover from the GPU hang. + * We intentionally don't call release_as_locked() here, because + * this would mess up with the active_cnt refcount. + */ + panthor_mmu_as_disable(ptdev, as->hw_slot.id, false); + drm_dev_exit(cookie); + } } - mutex_unlock(&ptdev->mmu->as.slots_lock); + + atomic_or(new_restrictions, &as->restrictions); } =20 static void panthor_as_unmap_pages(struct panthor_as *as, u64 iova, u64 si= ze) @@ -970,7 +998,9 @@ static void panthor_as_unmap_pages(struct panthor_as *a= s, u64 iova, u64 size) * so flag the VM unusable to make sure it's not going * to be used anymore. */ - panthor_as_declare_unusable(as); + panthor_as_restrict_usage_locked(as, + PANTHOR_AS_FORBID_USE | + PANTHOR_AS_FORBID_MAP); =20 /* If we don't make progress, we're screwed. That also means * something else prevents us from unmapping the region, but @@ -1046,7 +1076,9 @@ panthor_as_map_pages(struct panthor_as *as, u64 iova,= int prot, * table pages behind. */ panthor_as_unmap_pages(as, start_iova, iova - start_iova); - panthor_as_declare_unusable(as); + panthor_as_restrict_usage_locked(as, + PANTHOR_AS_FORBID_USE | + PANTHOR_AS_FORBID_MAP); return ret; } } @@ -1339,6 +1371,9 @@ static int panthor_as_prepare_map_op_ctx(struct panth= or_as_op_ctx *op_ctx, struct sg_table *sgt =3D NULL; int ret; =20 + if (atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_MAP) + return -EINVAL; + if (!bo) return -EINVAL; =20 @@ -1431,6 +1466,9 @@ static int panthor_as_prepare_unmap_op_ctx(struct pan= thor_as_op_ctx *op_ctx, u32 pt_count =3D 0; int ret; =20 + if (atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_UNMAP) + return -EINVAL; + memset(op_ctx, 0, sizeof(*op_ctx)); op_ctx->va.range =3D size; op_ctx->va.addr =3D va; @@ -1640,7 +1678,9 @@ static void panthor_vm_destroy(struct panthor_vm *vm) =20 as =3D vm->as; ptdev =3D container_of(as->base.drm, struct panthor_device, base); - vm->destroyed =3D true; + panthor_as_restrict_usage_locked(as, + PANTHOR_AS_FORBID_USE | + PANTHOR_AS_FORBID_MAP); =20 /* Tell scheduler to stop all GPU work related to this VM */ if (refcount_read(&as->active_cnt) > 0) @@ -2150,7 +2190,7 @@ struct panthor_heap_pool *panthor_vm_get_heap_pool(st= ruct panthor_vm *vm, bool c =20 mutex_lock(&vm->heaps.lock); if (!vm->heaps.pool && create) { - if (vm->destroyed) + if (panthor_vm_is_unusable(vm)) pool =3D ERR_PTR(-EINVAL); else pool =3D panthor_heap_pool_create(ptdev, vm); @@ -2769,7 +2809,7 @@ static int panthor_as_exec_op(struct panthor_as *as, .map.gem.offset =3D op->map.bo_offset, }; =20 - if (as->unusable) { + if (atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_MAP) { ret =3D -EINVAL; break; } @@ -2779,6 +2819,11 @@ static int panthor_as_exec_op(struct panthor_as *as, } =20 case DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP: + if (atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_UNMAP) { + ret =3D -EINVAL; + break; + } + ret =3D drm_gpuvm_sm_unmap(&as->base, as, op->va.addr, op->va.range); break; =20 @@ -2790,8 +2835,11 @@ static int panthor_as_exec_op(struct panthor_as *as, panthor_as_unlock_region(as); =20 out: - if (ret && flag_vm_unusable_on_failure) - panthor_as_declare_unusable(as); + if (ret && flag_vm_unusable_on_failure) { + panthor_as_restrict_usage_locked(as, + PANTHOR_AS_FORBID_USE | + PANTHOR_AS_FORBID_MAP); + } =20 as->op_ctx =3D NULL; mutex_unlock(&as->op_lock); @@ -3113,9 +3161,6 @@ panthor_vm_bind_job_create(struct drm_file *file, if (!vm) return ERR_PTR(-EINVAL); =20 - if (vm->destroyed || vm->as->unusable) - return ERR_PTR(-EINVAL); - job =3D kzalloc_obj(*job); if (!job) return ERR_PTR(-ENOMEM); --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 81AF04562A5 for ; Tue, 4 Aug 2026 10:10:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838208; cv=none; b=PclpJb2+bqpGV3N3MX6BhseEwRWOyMQtDo7x0mTjLj6CATtmX4jPOZNZKp2kqY3Fnvhh0miV2OnOP/z0U/gpa4lT+AkpJ8Vp1p1yh151Tx6VJ6K4CP5ZshuUFL57kcBNknNboDr0+r0BmRPR4m2fDAD/Jm4HPZb/GT35G64SwO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838208; c=relaxed/simple; bh=/ERn4ilSyg7dw4kv31czsKGd25efJ0U7glQoaAIJi6A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tAJnZxCT5lcypilSrd0KsVLlIy41DzQxKsr9hF0+m2qRiBjHHRu7hyGDNYQYZKjqWEko+ySSuFxRCxM/yX4ZY7qxvfNWVBCeXQe7sAiSBW344gpf1aJz9au6DpaFWuP4IxODqHZrjFMMzbL35VLhMAjMRa/y69EYN2fM7UwJ4fU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=D6YV13Mm; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="D6YV13Mm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838199; bh=/ERn4ilSyg7dw4kv31czsKGd25efJ0U7glQoaAIJi6A=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=D6YV13MmS+a+Jw5PHS/1d3unsBdP/pHPmCEFNm6SbbhHq4w0Za+4RK83U0IBCNYEk 4bQ3BRka2U8Ro3uVvSTMcDUBiXT5byop/44RG1w4M70jwnbzvkjXbPDE2T+VfHXmma b05fcrJlJ3LPjp4Vcw5dMmxboaoDM5l8okd/S/ThOh0RGttGLtLDrBAhizSrinnLss xnQX1eVGbD9xC/aypa+oz99xcYe259MWI10+5IEvkHp7/xyRcLTmkG3TndTD86RK6n K4/sq/LlMA9mbDwtJTZ3JvB1/svozbqcITUNcDZl+wqmFVqpU9VxRWXVwzI88MTcVN hbuVfG5lacK4g== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 9F74517E10C0; Tue, 04 Aug 2026 12:09:58 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:47 +0200 Subject: [PATCH 08/12] drm/panthor: Check AS state before disabling Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-8-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=1813; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=/ERn4ilSyg7dw4kv31czsKGd25efJ0U7glQoaAIJi6A=; b=KLSwPU31j4IxIZZaosfLTGtNLC47HwXvaFlQtYhVCaaLFeTwCtG+GtnrdpjHmWrgM4oU89yem D1kwcnG3fedASv3Qlm1sx8P90JY7rpTni+M0+gNmvz8MP49y8RxDeE3 X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= Use TRANSTAB =3D=3D 0 as a way to detect if an AS slot is idle. This allows us to make panthor_mmu_as_disable() a NOP when it's called after a SOFT_RESET, which will be needed for our unplug rework. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index 9a9025b02e28..1264c3ffa832 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -654,6 +654,10 @@ static int panthor_mmu_as_disable(struct panthor_devic= e *ptdev, u32 slot, =20 lockdep_assert_held(&ptdev->mmu->as.slots_lock); =20 + /* The AS was disabled already, nothing to do. */ + if (!gpu_read64(mmu->iomem, AS_TRANSTAB(slot))) + return 0; + panthor_mmu_irq_disable_events(&ptdev->mmu->irq, panthor_mmu_as_fault_mask(ptdev, slot)); =20 @@ -676,11 +680,17 @@ static int panthor_mmu_as_disable(struct panthor_devi= ce *ptdev, u32 slot, if (recycle_slot) return 0; =20 - gpu_write64(mmu->iomem, AS_TRANSTAB(slot), 0); - gpu_write64(mmu->iomem, AS_MEMATTR(slot), 0); gpu_write64(mmu->iomem, AS_TRANSCFG(slot), AS_TRANSCFG_ADRMODE_UNMAPPED); + ret =3D as_send_cmd_and_wait(ptdev, slot, AS_COMMAND_UPDATE); + if (ret) + return ret; =20 - return as_send_cmd_and_wait(ptdev, slot, AS_COMMAND_UPDATE); + /* We reset the other fields late to ensure that, if something fails, + * the page table is considered active (TRANSTAB !=3D NULL). + */ + gpu_write64(mmu->iomem, AS_MEMATTR(slot), 0); + gpu_write64(mmu->iomem, AS_TRANSTAB(slot), 0); + return 0; } =20 static u32 panthor_mmu_fault_mask(struct panthor_device *ptdev, u32 value) --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B696456E08 for ; Tue, 4 Aug 2026 10:10:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838209; cv=none; b=ZiLzLq3CD6Bs7lmncXEAgBx96/NRfCoryY52JtqFAw+1jcCxTBTZ1OVTCg5ClbwPcxsx9/rL2/SvqlHItuIAJn7v62v2P3khlJkQaUjMzje3eMsQwqXRTwDpeeQlU4zeAXE7CwmAlh11NKh2TCUEo5VWqw6nOxc0qQiHyVK+cOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838209; c=relaxed/simple; bh=RvHXpuZkvPZY2gpIgfn5uNsN8J9DCecmCGZwPoCSsFg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NaHdPvwBq1eQhbVApSqqSf+4zgRgKiUKOqdHkKS1l8kEgoPOgQI9J0MhDtxiHjeokajr3VHv93+9danVw7LR7abt8LWQOJZXgBrv7bTzUJWbb56auiNMD0EzY1R73xc1s8M5pGi9+sGhUHNz35emt4zzqbIBVI+2iBthNwNbuRw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=oCF/cfJc; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="oCF/cfJc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838199; bh=RvHXpuZkvPZY2gpIgfn5uNsN8J9DCecmCGZwPoCSsFg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=oCF/cfJcl6vyl5mZwhKaGnggWneqWt09JhjKBSUw68wsqE8j5BS5mEGsH48EnnWZ5 MmJSwRBivQVcuhryffDsT4EPVc2mXx8JbAQlOspflfUej4zfJsCv+NCG3GCeH4adrQ 6o6Zj+KwhaesCavnD0c9UiCeLWgtTRqh1s/Wsuq+uC4TfoTHXAyo4BTzP+8Av3AFQb ddzrXHdWxgOFIqABmK9Fdc9A2/v05Qn4MHAmM7ktn2Cbz7nrSHNGvGfzM6oaocs7m3 HhiOh8MszHODgb6+APsqDaoYBRw5gM5AsCix0eZ4g9sT7xO6gHW7PibNqoMW4MU8ew D6VlMARkaj6CQ== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 27B0A17E10F1; Tue, 04 Aug 2026 12:09:59 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:48 +0200 Subject: [PATCH 09/12] drm/panthor: Don't pre-allocate VMAs or page tables when preparing a full VM unmap Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-9-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=1151; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=RvHXpuZkvPZY2gpIgfn5uNsN8J9DCecmCGZwPoCSsFg=; b=QM8EMCXOVN/5GrmH1bGT4TXjDpDLBezEXKm4I/KyGMshzbRnrAFScnTSfL0nS4sQZ2m+BHDpa fbahScv2wmRDSHhOc6q1Bl3/BkWtl7lHghyL+fbqJOPKfx/V46bjFB3 X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= In the cleanup path, we unmap the full VA range to make sure things are clean before the VM is released. I'd rather not fail on memory allocation in that path, so let's make sure panthor_vm_pgtable_prepare_unmap_op_ctx() doesn't allocate VMAs or page tables when the unmap range matches the VM virtual address range. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index 1264c3ffa832..2ad8b15de0da 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1484,6 +1484,10 @@ static int panthor_as_prepare_unmap_op_ctx(struct pa= nthor_as_op_ctx *op_ctx, op_ctx->va.addr =3D va; op_ctx->flags =3D DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP; =20 + /* Unmap on the whole VM range don't need new VMAs or page tables. */ + if (va =3D=3D as->base.mm_start && size =3D=3D as->base.mm_range) + return 0; + /* Pre-allocate L3 page tables to account for the split-2M-block * situation on unmap. */ --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A06FA456E0E for ; Tue, 4 Aug 2026 10:10:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838210; cv=none; b=CyYwwT5WyjvKBUM5K7aXehXead7x+N2m17KDoEsJ0B0byEb0seSIwQW12UhAcKfTVFdwNyJm8c5H7IJnqz1hF7cqWToh6LX/v2I5KM3HinDXRuMNwprybqdWRvESTDQcYzHjrfmg2pTxg0PRF5U7JwsRQ8BQTwhgTDKaa+V/P/s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838210; c=relaxed/simple; bh=XaYyKv1F9ZM5pSCD5EAZxniq21grwW5GRmcaEWbO/70=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=s7rHI1SvRYtbFMoOSAs0U+CyBDeNihks87QT4Kc6RiapkalVF04H5hMdp/SlOIj9iQqyk1Xs5S7opovJlCOjrzXAthD3FAcWPedooLNiYEigc2QKN1F55vrtrtiozoLyjCYUgVbEhx9CM+5mcDVfpLbEvwOJ40AvUgkge1cJVy4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=kuWSd9aG; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="kuWSd9aG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838200; bh=XaYyKv1F9ZM5pSCD5EAZxniq21grwW5GRmcaEWbO/70=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=kuWSd9aG/dXZvBkp7mEutnDeYVGTFNgVZK4CvebFiBwwg17K3pcoQQ/OBbA4BwoNi N532rwbRhod2LzbCyAwoN2VY5RmTbfBsjX3KKqP3B3XTXDwf/rN5/i8NZxNzYArrFY SuFLLmjMaJ/5fZdwV9lZSg1liGbRaQtzpUtUrWsZ8NnGfLlsl7oc/nGNWSMBgwj0rB THsR3FOiKZvjYSY3EaS36SRG7YGhTz0AjZBWuSN5vHr+gqHkA/hHmdhoOTCc7mUb9e h2dgTccTA9GufjZQzO3W76rVb4J1lbXXcy9F8eqwP0/EJpA3ptd+L7lhubT7H3Y4Pn B3qI4EngmzPtw== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id A127717E1104; Tue, 04 Aug 2026 12:09:59 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:49 +0200 Subject: [PATCH 10/12] drm/panthor: Make the VM cleanup path more robust against UAF Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-10-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=10483; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=XaYyKv1F9ZM5pSCD5EAZxniq21grwW5GRmcaEWbO/70=; b=lVNksuBR5mrOjHCkfKLappJt8v7VUmCneys5C0TIPwMeFf2H9BIz27W34qbTnfp7tPAqGuatp lSLD0W8BW5+DZDdqpZtp5XTG9MZJParyHwj8VL6Kh0vsr4mTMS1BcbL X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= The VM cleanup tries to gracefully evict the page table from its AS slot to make sure the HW doesn't have access to the memory anymore. But it might happen that the eviction fails because the HW hung, and in that case, we have no guarantee that the HW won't access the memory until we've properly reset the GPU. Defer the cleanup of VMs after the reset is effective when this situation happens. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 226 +++++++++++++++++++++++++-----= ---- 1 file changed, 167 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index 2ad8b15de0da..de242ff124ed 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -92,6 +92,17 @@ struct panthor_mmu { * TLB/cache flushes. */ struct list_head lru_list; + + /** + * @cleanup_list: List containing VMs waiting for cleanup. + * + * This list is used to keep track of VMs that got released but + * couldn't be evicted from their AS slot because the HW hanged. + * In that case, we add the VM to the list, and wait for the next + * post_reset, at which point we're sure the HW is idle and the + * VM resources can go away. + */ + struct list_head cleanup_list; } as; =20 /** @vm: VMs management fields */ @@ -107,6 +118,12 @@ struct panthor_mmu { =20 /** @vm.wq: Workqueue used for the VM_BIND queues. */ struct workqueue_struct *wq; + + /** + * @vm.cleanup_work: Used to cleanup the VMs that are in + * panthor_mmu::as::cleanup_list. + */ + struct work_struct cleanup_work; } vm; }; =20 @@ -2059,6 +2076,35 @@ void panthor_mmu_pre_reset(struct panthor_device *pt= dev) mutex_unlock(&ptdev->mmu->vm.lock); } =20 +static void mmu_post_reset_cleanup(struct panthor_device *ptdev, bool on_u= nplug) +{ + guard(mutex)(&ptdev->mmu->as.slots_lock); + + /* Now that the reset is effective, we can assume that none of the + * AS slots are setup, and clear the faulty flags too. + */ + ptdev->mmu->as.alloc_mask =3D 0; + ptdev->mmu->as.faulty_mask =3D 0; + + for (u32 i =3D 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { + struct panthor_as *as =3D ptdev->mmu->as.slots[i].as; + + if (!as) + continue; + + panthor_as_release_hw_slot_locked(as); + + /* FIXME: We shouldn't drop the no-unmap restriction if + * we're in the unplug path and the device wasn't properly + * stopped with a SOFT_RESET. + */ + atomic_and(~PANTHOR_AS_FORBID_UNMAP, &as->restrictions); + } + + if (!list_empty(&ptdev->mmu->as.cleanup_list)) + queue_work(panthor_cleanup_wq, &ptdev->mmu->vm.cleanup_work); +} + /** * panthor_mmu_post_reset() - Restore things after a reset * @ptdev: Device. @@ -2070,22 +2116,7 @@ void panthor_mmu_post_reset(struct panthor_device *p= tdev) { struct panthor_vm *vm; =20 - mutex_lock(&ptdev->mmu->as.slots_lock); - - /* Now that the reset is effective, we can assume that none of the - * AS slots are setup, and clear the faulty flags too. - */ - ptdev->mmu->as.alloc_mask =3D 0; - ptdev->mmu->as.faulty_mask =3D 0; - - for (u32 i =3D 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { - struct panthor_as *as =3D ptdev->mmu->as.slots[i].as; - - if (as) - panthor_as_release_hw_slot_locked(as); - } - - mutex_unlock(&ptdev->mmu->as.slots_lock); + mmu_post_reset_cleanup(ptdev, false); =20 panthor_mmu_irq_resume(&ptdev->mmu->irq); =20 @@ -2098,58 +2129,26 @@ void panthor_mmu_post_reset(struct panthor_device *= ptdev) mutex_unlock(&ptdev->mmu->vm.lock); } =20 -static void panthor_vm_release(struct kref *kref) +static void vm_cleanup(struct panthor_vm *vm) { - struct panthor_vm *vm =3D container_of(kref, struct panthor_vm, refcount); struct panthor_as *as =3D vm->as; struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); =20 - /* Make sure the page table behind this VM doesn't participate in reclaim - * after that point, since we're about to release everything anyway. - */ - mutex_lock(&ptdev->base.gem_lru_mutex); - list_del_init(&as->reclaim.lru_node); - mutex_unlock(&ptdev->base.gem_lru_mutex); + if (!(atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_UNMAP)) { + /* Unmap everything in case some BOs were still mapped. */ + drm_WARN_ON(&ptdev->base, + panthor_vm_unmap_range(vm, as->base.mm_start, as->base.mm_range)); + } =20 - /* Unmap everything in case some BOs were still mapped. */ - drm_WARN_ON(&ptdev->base, - panthor_vm_unmap_range(vm, as->base.mm_start, as->base.mm_range)); - - mutex_lock(&vm->heaps.lock); - if (drm_WARN_ON(&ptdev->base, vm->heaps.pool)) - panthor_heap_pool_destroy(vm->heaps.pool); - mutex_unlock(&vm->heaps.lock); + scoped_guard(mutex, &vm->heaps.lock) { + if (drm_WARN_ON(&ptdev->base, vm->heaps.pool)) + panthor_heap_pool_destroy(vm->heaps.pool); + } mutex_destroy(&vm->heaps.lock); =20 - mutex_lock(&ptdev->mmu->vm.lock); - list_del(&vm->node); - /* Restore the scheduler state so we can call drm_sched_entity_destroy() - * and drm_sched_fini(). If get there, that means we have no job left - * and no new jobs can be queued, so we can start the scheduler without - * risking interfering with the reset. - */ - if (ptdev->mmu->vm.reset_in_progress) - panthor_vm_start(vm); - mutex_unlock(&ptdev->mmu->vm.lock); - drm_sched_entity_destroy(&vm->entity); drm_sched_fini(&vm->sched); =20 - mutex_lock(&vm->as->op_lock); - mutex_lock(&ptdev->mmu->as.slots_lock); - if (as->hw_slot.id >=3D 0) { - int cookie; - - if (drm_dev_enter(&ptdev->base, &cookie)) { - panthor_mmu_as_disable(ptdev, as->hw_slot.id, false); - drm_dev_exit(cookie); - } - - panthor_as_release_hw_slot_locked(as); - } - mutex_unlock(&ptdev->mmu->as.slots_lock); - mutex_unlock(&vm->as->op_lock); - if (vm->dummy) drm_gem_object_put(&vm->dummy->base); =20 @@ -2158,6 +2157,88 @@ static void panthor_vm_release(struct kref *kref) kfree(vm); } =20 +static bool vm_prep_for_cleanup(struct panthor_vm *vm) +{ + struct panthor_as *as =3D vm->as; + struct panthor_device *ptdev =3D container_of(as->base.drm, struct pantho= r_device, base); + bool ready_for_cleanup; + int cookie, ret; + + /* First we forbid any kind of use on the VM that's about to be + * released. UNMAP will be restored later if we manage to evict + * the page table from its AS slot. + */ + atomic_or(PANTHOR_AS_FORBID_USE | + PANTHOR_AS_FORBID_MAP | + PANTHOR_AS_FORBID_UNMAP, + &vm->as->restrictions); + + /* Make sure the page table behind this VM doesn't participate in reclaim + * after that point, since we're about to release everything anyway. + */ + scoped_guard(mutex, &ptdev->base.gem_lru_mutex) + list_del_init(&as->reclaim.lru_node); + + scoped_guard(mutex, &ptdev->mmu->vm.lock) { + /* Remove the VM from the list early, so it can't be seen by the VM list + * walkers after that point. + */ + list_del(&vm->node); + + /* Restore the scheduler state so we can call drm_sched_entity_destroy() + * and drm_sched_fini(). If get there, that means we have no job left + * and no new jobs can be queued, so we can start the scheduler without + * risking interfering with the reset. + */ + if (ptdev->mmu->vm.reset_in_progress) + panthor_vm_start(vm); + } + + if (!drm_dev_enter(&ptdev->base, &cookie)) { + guard(mutex)(&ptdev->mmu->as.slots_lock); + + /* We're in the unplug path and can't recover from + * that, so we just forcibly evict the pgtable. The + * no-unmap restriction will leak resources if + * we can't guarantee the HW stopped. + */ + if (as->hw_slot.id >=3D 0) + panthor_as_release_hw_slot_locked(as); + + return true; + } + + scoped_guard(mutex, &ptdev->mmu->as.slots_lock) { + if (as->hw_slot.id >=3D 0) { + ret =3D panthor_mmu_as_disable(ptdev, as->hw_slot.id, false); + if (!ret) { + panthor_as_release_hw_slot_locked(as); + } else { + list_add_tail(&vm->node, &ptdev->mmu->as.cleanup_list); + panthor_device_schedule_reset(ptdev); + } + } + + /* Page table is no longer resident, we can relax the no-unmap + * restriction. + */ + ready_for_cleanup =3D as->hw_slot.id < 0; + if (ready_for_cleanup) + atomic_and(~PANTHOR_AS_FORBID_UNMAP, &as->restrictions); + } + + drm_dev_exit(cookie); + return ready_for_cleanup; +} + +static void panthor_vm_release(struct kref *kref) +{ + struct panthor_vm *vm =3D container_of(kref, struct panthor_vm, refcount); + + if (vm_prep_for_cleanup(vm)) + vm_cleanup(vm); +} + /** * panthor_vm_put() - Release a reference on a VM * @vm: VM to release the reference on. Can be NULL. @@ -2762,7 +2843,11 @@ static void panthor_as_free(struct drm_gpuvm *gpuvm) { struct panthor_as *as =3D container_of(gpuvm, struct panthor_as, base); =20 - if (as->pt.ops) + /* If we get to that point and we're still not allowed to unmap, + * this means the HW is still running and has a access to the page + * table, so we just leak it to avoid UAF. + */ + if (as->pt.ops && !(atomic_read(&as->restrictions) & PANTHOR_AS_FORBID_UN= MAP)) free_io_pgtable_ops(as->pt.ops); =20 mutex_destroy(&as->op_lock); @@ -3488,6 +3573,27 @@ static void panthor_mmu_info_init(struct panthor_dev= ice *ptdev) ptdev->mmu_info.page_size_bitmap =3D SZ_4K | SZ_2M; } =20 +static void mmu_cleanup_vms_work(struct work_struct *work) +{ + struct panthor_mmu *mmu =3D + container_of(work, struct panthor_mmu, vm.cleanup_work); + struct panthor_vm *vm, *tmp; + LIST_HEAD(cleanup_list); + + /* Collect the VMs to cleanup first. */ + scoped_guard(mutex, &mmu->as.slots_lock) { + list_for_each_entry_safe(vm, tmp, &mmu->as.cleanup_list, node) { + if (vm->as->hw_slot.id < 0) + list_move_tail(&vm->node, &cleanup_list); + } + } + + list_for_each_entry_safe(vm, tmp, &cleanup_list, node) { + list_del(&vm->node); + vm_cleanup(vm); + } +} + /** * panthor_mmu_init() - Initialize the MMU logic. * @ptdev: Device. @@ -3506,7 +3612,9 @@ int panthor_mmu_init(struct panthor_device *ptdev) if (!mmu) return -ENOMEM; =20 + INIT_WORK(&mmu->vm.cleanup_work, mmu_cleanup_vms_work); INIT_LIST_HEAD(&mmu->as.lru_list); + INIT_LIST_HEAD(&mmu->as.cleanup_list); =20 ret =3D drmm_mutex_init(&ptdev->base, &mmu->as.slots_lock); if (ret) --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A10B2456E0F for ; Tue, 4 Aug 2026 10:10:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838210; cv=none; b=Dvn6i3IhawtEupK1Ovt6p2rgtGH8bahl5rEBDJ3WFYCq5npN438dtuUbkvE1a7ZZptVTU3ZDnCq5qk9r0cRmhiQEJvaJlM5G68q6D8JAgmylng0Y1uuTOqrPu/shIkA69dB6oEdXr6w41ysqvfhew98mhXWc1cfJPX98VUyAof0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838210; c=relaxed/simple; bh=AG99yjnzL0NwoPzc/SWSz0vsk8WoacIHE0yhynRxAM8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BObpTqaVK8XEZg9bLqbtb4Iz06YBvxVqasgbxB7/ZCqiqXvqmrlQp22/7zHSQvOlKiDfRVx4m+83uFbsmKmgNM9WW1i9VjLamzIvhWGTccLt80Cng+lmpILezRfRRq5NGdGM2cr0kExoiDjnt4+osbr5TdUKU2GY8Zf5OCOq/ec= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=E2BnaHun; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="E2BnaHun" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838200; bh=AG99yjnzL0NwoPzc/SWSz0vsk8WoacIHE0yhynRxAM8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=E2BnaHun/3nHNL7ZHo9l9xP1cThZdQ5aALpEGaGeK7w4vDct8GGamPFdwEYuqECNJ pIOSJ90vaDQgHX7rrZ7T+o+VznlIzwtH4+P7C2ne42/vhius7ruAktlntyK8Hr4Smx mS26dcFxkzCuj2OHh1o3BAhKmvcLT/6YFcM1NgDnzQSki7FXvGlf4Tv7ZivaRShDRs dqs/OlGkgmS5/GjHEDH6GO3C/Zah875PdGPr6l1640eboXu18sF5oNidnVHkxn3V77 IhoOObSPbfF5+Xj1arrcj5+1l7LO2swiUoiXm4472pYeiC3maeVGM3kROpX7ce7Ep6 Tlc337HpAFbeQ== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id 27E4A17E11E4; Tue, 04 Aug 2026 12:10:00 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:50 +0200 Subject: [PATCH 11/12] drm/panthor: Make the unplug logic more robust Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-11-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=13095; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=AG99yjnzL0NwoPzc/SWSz0vsk8WoacIHE0yhynRxAM8=; b=YXHe3jYuqwR3dET2Vey4nkp9/tYEpw0yuIWgQ4kTvSsAOLK6uI8+8swNyJdb/OiEiwNs8wf9f JbIKnSQaJv+AMSiP3bhsiz7KNGgZ1nHDPAMAkXI9rQhSVTkPyEyMYlB X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= The current unplug logic is broken in multiple subtle ways: 1. It assumes that the HW is still accessible in multiple places, which goes against the very concept of hot-unplug 2. It doesn't take into account the fact the stop is a failible operation, and that we theoretically have no guarantee that the HW is actually stopped after we've released the resources Those issues are hard to reason about because Mali GPUs are on a platform bus, which is not hot-pluggable, so they are in practice always accessible as long as we can enable their dependencies (clocks, power-domain, ...). The problem is, if the GPU is in such a bad state it can't properly reset/resume, there are various operations that can't be done properly, and the unplug logic is clearly not ready for that. And more importantly, if we can't guarantee the reset was effective, we have to assume the HW still has access to the resource we passed to it, meaning we can't return these resources to the system without risking a UAF. This patch does several things: - it resets the GPU before calling the _unplug() functions - it changes the _unplug() implementations to not touch the HW anymore - it let's each component know whether it should leak resources the HW might have its hands on at the time the unplug happens Unfortunately, those can't be split into multiple commits without breaking bisectability. Failures to reset the GPU in the unplug can be simulated with the new fake_unplug_failure debugfs knob: # echo 1 > /sys/kernel/debug/dri/128/fake_unplug_failure # # echo fb000000.gpu > /sys/module/panthor/drivers/platform\:panthor/unbind # Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 68 ++++++++++++++++++++++++++++= ++++ drivers/gpu/drm/panthor/panthor_device.h | 23 +++++++++++ drivers/gpu/drm/panthor/panthor_fw.c | 9 +---- drivers/gpu/drm/panthor/panthor_mmu.c | 53 ++++++++++++++++++------- drivers/gpu/drm/panthor/panthor_mmu.h | 1 + drivers/gpu/drm/panthor/panthor_sched.c | 17 ++++++++ 6 files changed, 149 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index b7c55a6f4f08..425990369b99 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -4,6 +4,7 @@ /* Copyright 2023 Collabora ltd. */ /* Copyright 2025 ARM Limited. All rights reserved. */ =20 +#include #include #include #include @@ -62,8 +63,40 @@ static int panthor_init_power(struct device *dev) return devm_pm_domain_attach_list(dev, NULL, &pd_list); } =20 +static int panthor_device_stop_before_unplug(struct panthor_device *ptdev) +{ + int ret; + + /* Make sure any further modification to the existing VMs are blocked + * before proceeding with the SOFT_RESET. + */ + panthor_mmu_freeze_before_unplug(ptdev); + + /* Core clock should be enough to issue a reset. */ + ret =3D clk_prepare_enable(ptdev->clks.core); + if (ret) + return ret; + + /* A successful soft-reset should guarantee that all components of the + * HW are off, meaning we can proceed with the rest of the unplug + * procedure. + */ + ret =3D panthor_hw_soft_reset(ptdev); + if (ret) + goto err_disable_core_clk; + + return ptdev->unplug.fake_failure ? -EIO : 0; + + +err_disable_core_clk: + clk_disable_unprepare(ptdev->clks.core); + return ret; +} + void panthor_device_unplug(struct panthor_device *ptdev) { + int ret; + /* This function can be called from two different path: the reset work * and the platform device remove callback. drm_dev_unplug() doesn't * deal with concurrent callers, so we have to protect drm_dev_unplug() @@ -90,6 +123,16 @@ void panthor_device_unplug(struct panthor_device *ptdev) /* Make sure we're not interrupted by resets while we're unplugging. */ disable_work_sync(&ptdev->reset.work); =20 + /* Do anything we can to stop the HW. If we can't guarantee that the HW + * is fully stopped, we also can't guarantee the resources it had access + * too won't be touched after the device is gone (clocks and regulators + * can be shared, and the HW might still be running behind our back). + */ + ret =3D panthor_device_stop_before_unplug(ptdev); + if (drm_WARN(&ptdev->base, ret, + "Couldn't stop the device, this might lead to resource leaks")) + ptdev->unplug.leak_active_resources =3D true; + /* We do the rest of the unplug with the unplug lock released, * future callers will wait on ptdev->unplug.done anyway. */ @@ -631,8 +674,33 @@ int panthor_device_suspend(struct device *dev) } =20 #ifdef CONFIG_DEBUG_FS +static int panthor_device_fake_unplug_failure_get(void *data, u64 *val) +{ + struct panthor_device *ptdev =3D data; + + *val =3D ptdev->unplug.fake_failure ? 1 : 0; + return 0; +} + +static int panthor_device_fake_unplug_failure_set(void *data, u64 val) +{ + struct panthor_device *ptdev =3D data; + + ptdev->unplug.fake_failure =3D val ? true : false; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(panthor_device_fake_unplug_failure_fops, + panthor_device_fake_unplug_failure_get, + panthor_device_fake_unplug_failure_set, "%llu\n"); + void panthor_device_debugfs_init(struct drm_minor *minor) { + struct panthor_device *ptdev =3D container_of(minor->dev, struct panthor_= device, base); + + debugfs_create_file("fake_unplug_failure", 0644, + minor->debugfs_root, ptdev, + &panthor_device_fake_unplug_failure_fops); panthor_mmu_debugfs_init(minor); panthor_gem_debugfs_init(minor); } diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/pan= thor/panthor_device.h index a6b1a2a5fca4..f960109f4b5b 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -264,6 +264,29 @@ struct panthor_device { * operation is done. */ struct completion done; + + /** + * @leak_active_resources: Sub-components should leak resources HW has + * access to. + * + * This is set to true when we can guarantee the HW has been fully stopp= ed + * in the unplug path. In that case, we'd rather leak resource than retu= rn + * them to the system with the risk that they might be accessed by the + * HW behind our back. + * + * This is particularly important for any piece of memory used by the GPU + * (MMU page tables, FW sections, group resources shared with the FW, + * any BO attached to an active VM, ...). + */ + bool leak_active_resources; + + /** + * @fake_failure: When true, pretend the SOFT_RESET in the unplug path f= ailed. + * + * This is important to check that we're doing the right thing in this v= ery + * unlikely case. + */ + bool fake_failure; } unplug; =20 /** @reset: Reset related fields. */ diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor= /panthor_fw.c index fc1a423e48a8..8d9fdc3202a1 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1285,11 +1285,9 @@ void panthor_fw_unplug(struct panthor_device *ptdev) =20 disable_delayed_work_sync(&ptdev->fw->watchdog.ping_work); =20 - if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) { - /* Make sure the IRQ handler cannot be called after that point. */ + /* Make sure the IRQ handler cannot be called after that point. */ + if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) panthor_job_irq_suspend(&ptdev->fw->irq); - panthor_fw_stop(ptdev); - } =20 list_for_each_entry(section, &ptdev->fw->sections, node) panthor_kernel_bo_destroy(section->mem); @@ -1301,9 +1299,6 @@ void panthor_fw_unplug(struct panthor_device *ptdev) */ panthor_vm_put(ptdev->fw->vm); ptdev->fw->vm =3D NULL; - - if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) - panthor_hw_l2_power_off(ptdev); } =20 /** diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index de242ff124ed..9252a279a47b 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -2094,11 +2094,12 @@ static void mmu_post_reset_cleanup(struct panthor_d= evice *ptdev, bool on_unplug) =20 panthor_as_release_hw_slot_locked(as); =20 - /* FIXME: We shouldn't drop the no-unmap restriction if - * we're in the unplug path and the device wasn't properly - * stopped with a SOFT_RESET. + /* If this is an unplug situation and leak_active_resources is + * true, we have to keep the no-unmap restriction to force a + * resource leak. */ - atomic_and(~PANTHOR_AS_FORBID_UNMAP, &as->restrictions); + if (!on_unplug || !ptdev->unplug.leak_active_resources) + atomic_and(~PANTHOR_AS_FORBID_UNMAP, &as->restrictions); } =20 if (!list_empty(&ptdev->mmu->as.cleanup_list)) @@ -2195,8 +2196,19 @@ static bool vm_prep_for_cleanup(struct panthor_vm *v= m) } =20 if (!drm_dev_enter(&ptdev->base, &cookie)) { + /* Device is gone, take the unplug lock to make sure + * panthor_device_stop_before_unplug() has run and + * ::leak_active_resources is valid. + */ + guard(mutex)(&ptdev->unplug.lock); guard(mutex)(&ptdev->mmu->as.slots_lock); =20 + /* If we're not asked to leak resources, drop the + * no-unmap restriction. + */ + if (!ptdev->unplug.leak_active_resources) + atomic_and(~PANTHOR_AS_FORBID_UNMAP, &as->restrictions); + /* We're in the unplug path and can't recover from * that, so we just forcibly evict the pgtable. The * no-unmap restriction will leak resources if @@ -3538,6 +3550,27 @@ panthor_mmu_reclaim_priv_bos(struct panthor_device *= ptdev, return freed; } =20 +void panthor_mmu_freeze_before_unplug(struct panthor_device *ptdev) +{ + struct panthor_vm *vm; + + guard(mutex)(&ptdev->mmu->vm.lock); + guard(mutex)(&ptdev->mmu->as.slots_lock); + list_for_each_entry(vm, &ptdev->mmu->vm.list, node) { + /* We intentionally don't use panthor_vm_restrict_usage_locked() here + * because we don't want the AS eviction to happen, otherwise we + * won't be able to know which VMs were active at the time the + * unplug happened. Unmap is forbidden to make sure any modification + * to the VM is blocked after that point. This way, if the reset + * fails, we're able to flag VMs that need to leak their resources. + */ + atomic_or(PANTHOR_AS_FORBID_USE | + PANTHOR_AS_FORBID_MAP | + PANTHOR_AS_FORBID_UNMAP, + &vm->as->restrictions); + } +} + /** * panthor_mmu_unplug() - Unplug the MMU logic * @ptdev: Device. @@ -3550,17 +3583,7 @@ void panthor_mmu_unplug(struct panthor_device *ptdev) if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) panthor_mmu_irq_suspend(&ptdev->mmu->irq); =20 - mutex_lock(&ptdev->mmu->as.slots_lock); - for (u32 i =3D 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { - struct panthor_as *as =3D ptdev->mmu->as.slots[i].as; - - if (as) { - drm_WARN_ON(&ptdev->base, - panthor_mmu_as_disable(ptdev, i, false)); - panthor_as_release_hw_slot_locked(as); - } - } - mutex_unlock(&ptdev->mmu->as.slots_lock); + mmu_post_reset_cleanup(ptdev, true); } =20 static void panthor_mmu_release_wq(struct drm_device *ddev, void *res) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/pantho= r/panthor_mmu.h index 3522fbbce369..efe6e07936a0 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -18,6 +18,7 @@ struct panthor_vma; struct panthor_mmu; =20 int panthor_mmu_init(struct panthor_device *ptdev); +void panthor_mmu_freeze_before_unplug(struct panthor_device *ptdev); void panthor_mmu_unplug(struct panthor_device *ptdev); void panthor_mmu_pre_reset(struct panthor_device *ptdev); void panthor_mmu_post_reset(struct panthor_device *ptdev); diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index 5832dccfc093..adc2c05251e9 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -4069,6 +4069,23 @@ void panthor_sched_unplug(struct panthor_device *ptd= ev) disable_work_sync(&sched->sync_upd_work); =20 mutex_lock(&sched->lock); + + /* Do a pass on the on-slot groups, and schedule termination. */ + for (u32 i =3D 0; i < sched->csg_slot_count; i++) { + struct panthor_csg_slot *csg_slot =3D &sched->csg_slots[i]; + struct panthor_group *group =3D csg_slot->group; + + if (!group) + continue; + + group_get(group); + group->state =3D PANTHOR_CS_GROUP_TERMINATED; + group_unbind_locked(group); + list_del_init(&group->wait_node); + group_queue_work(group, term); + group_put(group); + } + if (sched->pm.has_ref) { pm_runtime_put(ptdev->base.dev); sched->pm.has_ref =3D false; --=20 2.55.0 From nobody Fri Oct 2 06:58:27 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80F32456E09 for ; Tue, 4 Aug 2026 10:10:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838209; cv=none; b=VmUIPsmrV5K4oFuUhLzY7jL9/CnbZhzJaL+ptO8CcTq8fI9Ck+F9UdmuMULRHL9f1M5viM2v2EoJBtT9evrYun/J9NS9Bj1c7VF/FtXKuFRZXklW7uRbrdD4o2KWZmANmeDmOAEv3NBQUuQQx+OZznSxdeXu27GFK7ifoHTmdf0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785838209; c=relaxed/simple; bh=IxNTkuNmGbCBaAyYnmtQYnwSXqfjegGebkYKXwCgjrg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oP1hnm9zHauPZO5Fn8CPw/wJrEXVxZgUpsyKTDdrfmd/0a1JI48694plT5qaRq/y6EGO/ducHOBJRBVVXQwEj4apH7IcA+ueP0+5XsFmiXYusAxqU5b8Jgp5qJYzOMMI9UtMZrI1uGIt+ApfRjsF7zZa2yizGLyTAet13DBEm+k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=Yuke0yYE; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="Yuke0yYE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1785838201; bh=IxNTkuNmGbCBaAyYnmtQYnwSXqfjegGebkYKXwCgjrg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Yuke0yYE+/10pWP7b+cwQySavj6vjESx0QFno7SVGWXnmOl2SW/V+oIRJ+oqZA9QV ahqNzWLJB9rBsXfpX0Wmk9qVivIDo1q6bk9tpFRHoZ+rAyzFzU7RwUd1BhCGIiEFya 4ZTEp/4f/NZIiiNMIJJ6eCnTLKQmi9uY5kerYYeT2DyzcNmBnRWLoFJJkhYt4sF1er SY265tAiZp0G9luIlPzvKGoYjcTTYBiPGzJVErUZUbLIkMvqKfJ457Pf09igM/9ORd pmhoSC2zd6h2iZfLCBC8F9vFVXAIRingFSzUvM7LlU5MD7XVtKg/HSBUiSVUxVvgdt 3q/IdJ4C1Q02w== Received: from fedora-21.home (unknown [100.64.0.11]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: bbrezillon) by bali.collaboradmins.com (Postfix) with ESMTPSA id A2E2E17E11E6; Tue, 04 Aug 2026 12:10:00 +0200 (CEST) From: Boris Brezillon Date: Tue, 04 Aug 2026 12:09:51 +0200 Subject: [PATCH 12/12] drm/panthor: Fix unplug in the reset path Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260804-panthor-unplug-fixes-v1-12-abbbd2d41b13@collabora.com> References: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> In-Reply-To: <20260804-panthor-unplug-fixes-v1-0-abbbd2d41b13@collabora.com> To: Steven Price , Liviu Dudau Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Boris Brezillon X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1785838194; l=6038; i=boris.brezillon@collabora.com; s=20260429; h=from:subject:message-id; bh=IxNTkuNmGbCBaAyYnmtQYnwSXqfjegGebkYKXwCgjrg=; b=0VypsmCoAzBuVv0BKjNGLP64WEoTBKF/lMs5VN7jfGKXjMwDuSz3xS3E30iK8W9QRaTbFpUc6 Cma5b7gsAeDAzywB2+dlFxjKsp+jrRmA6OtJW5+W2OGHg5ACbOFV6y6 X-Developer-Key: i=boris.brezillon@collabora.com; a=ed25519; pk=eN+ORdOgQY7d5U+0kA8h5bf67XdD8bhKbjD/TCHexSY= We can't use disable_work_sync() if panthor_device_unplug() is called from the reset work or we'll deadlock. Pass a from_reset_work bool to the panthor_device_unplug() function and lower the disable_work_sync() to a disable_work() in that case. We also add debugfs knobs to simulate this situation. Maybe we should use a separate work and call device_release_driver() instead of calling panthor_device_unplug() directly. This would allow us to actually detach the device from panthor so it can later be re-attached without an explicit unbind/bind or rmmod/modprobe sequence. The problem is, this gets racy if the device is manually unbound/rebound, and it's hard to fix that race, so let's keep this for later. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 54 ++++++++++++++++++++++++++++= +--- drivers/gpu/drm/panthor/panthor_device.h | 10 +++++- drivers/gpu/drm/panthor/panthor_drv.c | 2 +- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index 425990369b99..d350bda58bb3 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -93,7 +93,7 @@ static int panthor_device_stop_before_unplug(struct panth= or_device *ptdev) return ret; } =20 -void panthor_device_unplug(struct panthor_device *ptdev) +void panthor_device_unplug(struct panthor_device *ptdev, bool from_reset_w= ork) { int ret; =20 @@ -121,7 +121,10 @@ void panthor_device_unplug(struct panthor_device *ptde= v) drm_dev_unplug(&ptdev->base); =20 /* Make sure we're not interrupted by resets while we're unplugging. */ - disable_work_sync(&ptdev->reset.work); + if (!from_reset_work) + disable_work_sync(&ptdev->reset.work); + else + disable_work(&ptdev->reset.work); =20 /* Do anything we can to stop the HW. If we can't guarantee that the HW * is fully stopped, we also can't guarantee the resources it had access @@ -189,13 +192,16 @@ static void panthor_device_reset_work(struct work_str= uct *work) panthor_hw_soft_reset(ptdev); panthor_hw_l2_power_on(ptdev); panthor_mmu_post_reset(ptdev); - ret =3D panthor_fw_post_reset(ptdev); + if (ptdev->reset.fake_failure) + ret =3D -EIO; + else + ret =3D panthor_fw_post_reset(ptdev); atomic_set(&ptdev->reset.pending, 0); panthor_sched_post_reset(ptdev, ret !=3D 0); drm_dev_exit(cookie); =20 if (ret) { - panthor_device_unplug(ptdev); + panthor_device_unplug(ptdev, true); drm_err(&ptdev->base, "Failed to boot MCU after reset, making device unu= sable."); } } @@ -694,6 +700,40 @@ DEFINE_DEBUGFS_ATTRIBUTE(panthor_device_fake_unplug_fa= ilure_fops, panthor_device_fake_unplug_failure_get, panthor_device_fake_unplug_failure_set, "%llu\n"); =20 +static int panthor_device_fake_fw_reset_failure_get(void *data, u64 *val) +{ + struct panthor_device *ptdev =3D data; + + *val =3D ptdev->reset.fake_failure ? 1 : 0; + return 0; +} + +static int panthor_device_fake_fw_reset_failure_set(void *data, u64 val) +{ + struct panthor_device *ptdev =3D data; + + ptdev->reset.fake_failure =3D val ? true : false; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(panthor_device_fake_fw_reset_failure_fops, + panthor_device_fake_fw_reset_failure_get, + panthor_device_fake_fw_reset_failure_set, "%llu\n"); + +static ssize_t panthor_device_reset_file_write(struct file *file, + const char __user *, size_t size, + loff_t *) +{ + struct panthor_device *ptdev =3D file_inode(file)->i_private; + + panthor_device_schedule_reset(ptdev); + return size; +} + +static const struct debugfs_short_fops panthor_device_reset_fops =3D { + .write =3D panthor_device_reset_file_write, +}; + void panthor_device_debugfs_init(struct drm_minor *minor) { struct panthor_device *ptdev =3D container_of(minor->dev, struct panthor_= device, base); @@ -701,6 +741,12 @@ void panthor_device_debugfs_init(struct drm_minor *min= or) debugfs_create_file("fake_unplug_failure", 0644, minor->debugfs_root, ptdev, &panthor_device_fake_unplug_failure_fops); + debugfs_create_file("fake_fw_reset_failure", 0644, + minor->debugfs_root, ptdev, + &panthor_device_fake_fw_reset_failure_fops); + debugfs_create_file("reset", 0200, + minor->debugfs_root, ptdev, + &panthor_device_reset_fops); panthor_mmu_debugfs_init(minor); panthor_gem_debugfs_init(minor); } diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/pan= thor/panthor_device.h index f960109f4b5b..7d3db80fdfb6 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -310,6 +310,14 @@ struct panthor_device { * all FW sections to make sure we start from a fresh state. */ bool fast; + + /** + * @fake_failure: When true, pretend the FW boot in the reset path faile= d. + * + * This is important to check that we're doing the right thing in this v= ery + * unlikely case. + */ + bool fake_failure; } reset; =20 /** @pm: Power management related data. */ @@ -398,7 +406,7 @@ struct panthor_file { }; =20 int panthor_device_init(struct panthor_device *ptdev); -void panthor_device_unplug(struct panthor_device *ptdev); +void panthor_device_unplug(struct panthor_device *ptdev, bool from_reset_w= ork); =20 /** * panthor_device_schedule_reset() - Schedules a reset operation diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/pantho= r/panthor_drv.c index 924a7ecd3733..730f7996985c 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1827,7 +1827,7 @@ static void panthor_remove(struct platform_device *pd= ev) { struct panthor_device *ptdev =3D platform_get_drvdata(pdev); =20 - panthor_device_unplug(ptdev); + panthor_device_unplug(ptdev, false); } =20 static ssize_t profiling_show(struct device *dev, --=20 2.55.0