From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7FC0339A061 for ; Sun, 12 Jul 2026 13:54:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864493; cv=none; b=RT7WY5lGa0r2xry076wLJmaU0ydB8XLVBDtamw/Frv9K5wRgB0MzytzWSON4zYqcOdDxxCQ3+V2vfh3EpGqk/4WYJ6pC0aRcGviGZA0d1Kg9Zua1ocLr+UX08fBDXOHMfiKFLMnk609W11vsZBNwcGfh1CPhx1JNPB7KM2hWp2I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864493; c=relaxed/simple; bh=r0aRd83PxUdqrq7QseJnx2XvSdqq33zFHUbq1D38tOo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HCdGq7CZfnMaIxDHUiXG7rKn3JqUmi+Q6QwijwROV2aQ3Jvjy/g+Ijc23jTX+CI/v/FMzQho+5IX7OGzzt8sVatC7RaL6aWbSpEUbRckx7XYNTABJXjnZP+pHsjIaQKGYgbNRBSEhbhk+s2H+a1jnsMfeQuyJt+vl/Hk18OJatQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=SvLyWJeh; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="SvLyWJeh" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9F8A21BB2; Sun, 12 Jul 2026 06:54:46 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5F42C3F7D8; Sun, 12 Jul 2026 06:54:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864490; bh=r0aRd83PxUdqrq7QseJnx2XvSdqq33zFHUbq1D38tOo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SvLyWJehFCcvFwhSx+sDjCah9sQfbzuhqSkzUeGlmaosIDGgHmlCD0pKx9FG6IDjl mRZpTXlp14UG16uu/i9WybsHYvFqYBupBEgeOCG7SR/gzLy7cmVx6+FDOklcAX0U3e tH8ccjzIYE3k/EdCKe6FNtyTWhnMCQKYgxo5JC7w= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Ketil Johnsen Subject: [PATCH v2 1/7] drm/panthor: De-duplicate FW memory section sync Date: Sun, 12 Jul 2026 15:54:33 +0200 Message-ID: <20260712135439.1546950-2-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Handle the sync to device of FW memory sections inside panthor_fw_init_section_mem() so that the callers do not have to. This small improvement is also critical for protected FW sections, so we avoid issuing memory transactions to protected memory from CPU running in normal mode. Reviewed-by: Boris Brezillon Reviewed-by: Liviu Dudau Signed-off-by: Ketil Johnsen Reviewed-by: Steven Price --- drivers/gpu/drm/panthor/panthor_fw.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor= /panthor_fw.c index 986151681b246..389f9182fac16 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -449,6 +449,7 @@ static void panthor_fw_init_section_mem(struct panthor_= device *ptdev, struct panthor_fw_section *section) { bool was_mapped =3D !!section->mem->kmap; + struct sg_table *sgt; int ret; =20 if (!section->data.size && @@ -467,6 +468,11 @@ static void panthor_fw_init_section_mem(struct panthor= _device *ptdev, =20 if (!was_mapped) panthor_kernel_bo_vunmap(section->mem); + + /* An sgt should have been requested when the kernel BO was GPU-mapped. */ + sgt =3D to_panthor_bo(section->mem->obj)->dmap.sgt; + if (!drm_WARN_ON_ONCE(&ptdev->base, !sgt)) + dma_sync_sgtable_for_device(ptdev->base.dev, sgt, DMA_TO_DEVICE); } =20 /** @@ -629,7 +635,6 @@ static int panthor_fw_load_section_entry(struct panthor= _device *ptdev, section_size =3D hdr.va.end - hdr.va.start; if (section_size) { u32 cache_mode =3D hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK; - struct panthor_gem_object *bo; u32 vm_map_flags =3D 0; u64 va =3D hdr.va.start; =20 @@ -666,14 +671,6 @@ static int panthor_fw_load_section_entry(struct pantho= r_device *ptdev, } =20 panthor_fw_init_section_mem(ptdev, section); - - bo =3D to_panthor_bo(section->mem->obj); - - /* An sgt should have been requested when the kernel BO was GPU-mapped. = */ - if (drm_WARN_ON_ONCE(&ptdev->base, !bo->dmap.sgt)) - return -EINVAL; - - dma_sync_sgtable_for_device(ptdev->base.dev, bo->dmap.sgt, DMA_TO_DEVICE= ); } =20 if (hdr.va.start =3D=3D CSF_MCU_SHARED_REGION_START) @@ -727,17 +724,10 @@ panthor_reload_fw_sections(struct panthor_device *ptd= ev, bool full_reload) struct panthor_fw_section *section; =20 list_for_each_entry(section, &ptdev->fw->sections, node) { - struct sg_table *sgt; - if (!full_reload && !(section->flags & CSF_FW_BINARY_IFACE_ENTRY_WR)) continue; =20 panthor_fw_init_section_mem(ptdev, section); - - /* An sgt should have been requested when the kernel BO was GPU-mapped. = */ - sgt =3D to_panthor_bo(section->mem->obj)->dmap.sgt; - if (!drm_WARN_ON_ONCE(&ptdev->base, !sgt)) - dma_sync_sgtable_for_device(ptdev->base.dev, sgt, DMA_TO_DEVICE); } } =20 --=20 2.43.0 From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id AA6E03AC0CC for ; Sun, 12 Jul 2026 13:54:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864496; cv=none; b=Ap/n4fxEgvaZZi7YytNPl+Q5Rxjg6d4C9bczXP2DCp1X6e1aGaNG7nSwyYZ/1dFxyTxSh1L4woL4awOwavdDvLgPbSn4ntoJU4esIhOm92Z1FUhr2RbMsm9FZyvGtvq/gH8VB2NP0KVy6nyZg+P3ZTEStul7siXvCKC7HIhrTHI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864496; c=relaxed/simple; bh=AECzyyBsTPn756pAm2Zz9lalYMCyXNCh2wmchjJwJ2U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lz6v3MvWBWGCOPBbaPw96Qm+M2PWAUOWiIk8tCKRNb+tHwF0z38J/XczXcN7YcBUPk3TVpzPbNd2FhGvuDzhJu0lleHO+CSR1OjA568hGufu46B8FwaOHnRClV1C+3H00KiRW07UCnnmzi/DLLilgr6bews2UBXkAvelkQESgX8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=s0N/ZBXJ; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="s0N/ZBXJ" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BA9981684; Sun, 12 Jul 2026 06:54:49 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 50D763F7D8; Sun, 12 Jul 2026 06:54:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864494; bh=AECzyyBsTPn756pAm2Zz9lalYMCyXNCh2wmchjJwJ2U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s0N/ZBXJy5fuRpuaniv4sXBx6YYhuILtmmvJg528CVmD7y8kJSbVbCwqN029CeQVb Z/pHM5f4ETKNVev9Qg/BGBNC/+d/1jp2GyPR/zIYNcUqBLWkRYnNoE6fMgA88gl69o SvHzlpDURl5NRV9Shz84O+Ix1ZGgOK22l7TS/auU= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Florent Tomasin , Ketil Johnsen Subject: [PATCH v2 2/7] drm/panthor: Minor scheduler refactoring Date: Sun, 12 Jul 2026 15:54:34 +0200 Message-ID: <20260712135439.1546950-3-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Florent Tomasin Refactor parts of the group scheduling logic into new helper functions. This will simplify addition of the protected mode feature. Remove redundant assignments of csg_slot. Signed-off-by: Florent Tomasin Co-developed-by: Ketil Johnsen Signed-off-by: Ketil Johnsen --- drivers/gpu/drm/panthor/panthor_sched.c | 126 ++++++++++++++---------- 1 file changed, 74 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index 5b34032deff81..465f1b86249f8 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -2267,12 +2267,75 @@ tick_ctx_cleanup(struct panthor_scheduler *sched, } } =20 +static void +tick_ctx_evict_group(struct panthor_scheduler *sched, + struct panthor_csg_slots_upd_ctx *upd_ctx, + struct panthor_group *group) +{ + struct panthor_device *ptdev =3D sched->ptdev; + + if (drm_WARN_ON(&ptdev->base, group->csg_id < 0)) + return; + + csgs_upd_ctx_queue_reqs(ptdev, upd_ctx, group->csg_id, + group_can_run(group) ? + CSG_STATE_SUSPEND : CSG_STATE_TERMINATE, + CSG_STATE_MASK); +} + +static void +tick_ctx_reschedule_group(struct panthor_scheduler *sched, + struct panthor_csg_slots_upd_ctx *upd_ctx, + struct panthor_group *group, + int new_csg_prio) +{ + struct panthor_device *ptdev =3D sched->ptdev; + struct panthor_fw_csg_iface *csg_iface; + struct panthor_csg_slot *csg_slot; + + if (group->csg_id < 0) + return; + + csg_iface =3D panthor_fw_get_csg_iface(ptdev, group->csg_id); + csg_slot =3D &sched->csg_slots[group->csg_id]; + + if (csg_slot->priority !=3D new_csg_prio) { + panthor_fw_update_reqs(csg_iface, endpoint_req, + CSG_EP_REQ_PRIORITY(new_csg_prio), + CSG_EP_REQ_PRIORITY_MASK); + csgs_upd_ctx_queue_reqs(ptdev, upd_ctx, group->csg_id, + csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG, + CSG_ENDPOINT_CONFIG); + } +} + +static void +tick_ctx_schedule_group(struct panthor_scheduler *sched, + struct panthor_csg_slots_upd_ctx *upd_ctx, + struct panthor_group *group, + int csg_id, int csg_prio) +{ + struct panthor_device *ptdev =3D sched->ptdev; + struct panthor_fw_csg_iface *csg_iface =3D + panthor_fw_get_csg_iface(ptdev, csg_id); + + group_bind_locked(group, csg_id); + csg_slot_prog_locked(ptdev, csg_id, csg_prio); + + csgs_upd_ctx_queue_reqs(ptdev, upd_ctx, csg_id, + group->state =3D=3D PANTHOR_CS_GROUP_SUSPENDED ? + CSG_STATE_RESUME : CSG_STATE_START, + CSG_STATE_MASK); + csgs_upd_ctx_queue_reqs(ptdev, upd_ctx, csg_id, + csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG, + CSG_ENDPOINT_CONFIG); +} + static void tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_= ctx *ctx) { struct panthor_group *group, *tmp; struct panthor_device *ptdev =3D sched->ptdev; - struct panthor_csg_slot *csg_slot; int prio, new_csg_prio =3D MAX_CSG_PRIO, i; u32 free_csg_slots =3D 0; struct panthor_csg_slots_upd_ctx upd_ctx; @@ -2282,44 +2345,13 @@ tick_ctx_apply(struct panthor_scheduler *sched, str= uct panthor_sched_tick_ctx *c =20 for (prio =3D PANTHOR_CSG_PRIORITY_COUNT - 1; prio >=3D 0; prio--) { /* Suspend or terminate evicted groups. */ - list_for_each_entry(group, &ctx->old_groups[prio], run_node) { - bool term =3D !group_can_run(group); - int csg_id =3D group->csg_id; - - if (drm_WARN_ON(&ptdev->base, csg_id < 0)) - continue; - - csg_slot =3D &sched->csg_slots[csg_id]; - csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, - term ? CSG_STATE_TERMINATE : CSG_STATE_SUSPEND, - CSG_STATE_MASK); - } + list_for_each_entry(group, &ctx->old_groups[prio], run_node) + tick_ctx_evict_group(sched, &upd_ctx, group); =20 /* Update priorities on already running groups. */ - list_for_each_entry(group, &ctx->groups[prio], run_node) { - struct panthor_fw_csg_iface *csg_iface; - int csg_id =3D group->csg_id; - - if (csg_id < 0) { - new_csg_prio--; - continue; - } - - csg_slot =3D &sched->csg_slots[csg_id]; - csg_iface =3D panthor_fw_get_csg_iface(ptdev, csg_id); - if (csg_slot->priority =3D=3D new_csg_prio) { - new_csg_prio--; - continue; - } - - panthor_fw_csg_endpoint_req_update(ptdev, csg_iface, - CSG_EP_REQ_PRIORITY(new_csg_prio), - CSG_EP_REQ_PRIORITY_MASK); - csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, - csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG, - CSG_ENDPOINT_CONFIG); - new_csg_prio--; - } + list_for_each_entry(group, &ctx->groups[prio], run_node) + tick_ctx_reschedule_group(sched, &upd_ctx, group, + new_csg_prio--); } =20 ret =3D csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); @@ -2355,28 +2387,18 @@ tick_ctx_apply(struct panthor_scheduler *sched, str= uct panthor_sched_tick_ctx *c for (prio =3D PANTHOR_CSG_PRIORITY_COUNT - 1; prio >=3D 0; prio--) { list_for_each_entry(group, &ctx->groups[prio], run_node) { int csg_id =3D group->csg_id; - struct panthor_fw_csg_iface *csg_iface; + int csg_prio =3D new_csg_prio--; =20 - if (csg_id >=3D 0) { - new_csg_prio--; + if (csg_id >=3D 0) continue; - } =20 csg_id =3D ffs(free_csg_slots) - 1; if (drm_WARN_ON(&ptdev->base, csg_id < 0)) break; =20 - csg_iface =3D panthor_fw_get_csg_iface(ptdev, csg_id); - csg_slot =3D &sched->csg_slots[csg_id]; - group_bind_locked(group, csg_id); - csg_slot_prog_locked(ptdev, csg_id, new_csg_prio--); - csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, - group->state =3D=3D PANTHOR_CS_GROUP_SUSPENDED ? - CSG_STATE_RESUME : CSG_STATE_START, - CSG_STATE_MASK); - csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, - csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG, - CSG_ENDPOINT_CONFIG); + tick_ctx_schedule_group(sched, &upd_ctx, group, csg_id, + csg_prio); + free_csg_slots &=3D ~BIT(csg_id); } } --=20 2.43.0 From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7D0403AC0D0 for ; Sun, 12 Jul 2026 13:54:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864499; cv=none; b=Acfe6ZKE5EjEIPNE2+ApCUMdEM3IpuppmLwnUh8k7IuNFdjxjXoHG5pie6FQBQduwj5UPi3ZqOVpZIL/Z73FXKKTcdTX+rJXqkDSVON0d+B0aa76l4j/SOkqzkrGyBS7+zraHi3ZQBFRkKtFVHqx+EjX5c1So+UPM29aPn/OV+s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864499; c=relaxed/simple; bh=0vuEUipr2Pz5kr1HUOhPNLBdi7tGEKWJIfEyTufgknk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=U9/x0W1T/2w3OKisZgGJ9icdgAPFbdp/EPBSXsgaVwKXmjNti5LTWgJrhKeJ5q6t5Cd/v/xAicp0gxxnvO+CQYOXTdzVD8nZrKyA1Di1MDidP3bhQ8TjvuNeCijDk5xwnseiMsesGLvBfWOpHj32x2Fw16JkjV9sSRsXuQSxJwc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=X4rRAFmd; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="X4rRAFmd" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AA4CB1684; Sun, 12 Jul 2026 06:54:52 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6BA3D3F7D8; Sun, 12 Jul 2026 06:54:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864496; bh=0vuEUipr2Pz5kr1HUOhPNLBdi7tGEKWJIfEyTufgknk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X4rRAFmdcWdGFmpEc9NIlJyFEXssEKPnZ7hthJApP0Y6TY3kKCHJlldlIwucIZAmx 6eaklnLBeZhZmtxxVpV8MwCv7tn1rIevg7EJr82RDkbN8q6EUzUJ2tiBsbRW390R+e l5yf+VPSPkAOy4RtNWGihf+s4lJUbl70yP65YRoo= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Ketil Johnsen Subject: [PATCH v2 3/7] drm/panthor: Explicit expansion of locked VM region Date: Sun, 12 Jul 2026 15:54:35 +0200 Message-ID: <20260712135439.1546950-4-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Currently the panthor_vm_lock_region() function will implicitly expand an already locked VM region. This can be problematic because the caller do not reliably know if it needs to call panthor_vm_unlock_region() or not. Worth noting, there is currently no known issues with this as the code is written today. This change introduces panthor_vm_expand_region() which will only work if there is already a locked VM region. This again means that the original lock and unlock functions can work as a pair. This pairing is needed for subsequent protected memory changes. Signed-off-by: Ketil Johnsen --- drivers/gpu/drm/panthor/panthor_mmu.c | 87 +++++++++++++++++++-------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index 1f6b9242279c2..b82b01013611c 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1774,20 +1774,49 @@ static const char *access_type_name(struct panthor_= device *ptdev, } } =20 +static int panthor_vm_apply_as_lock(struct panthor_vm *vm, u64 region) +{ + struct panthor_device *ptdev =3D vm->ptdev; + + lockdep_assert_held(&ptdev->mmu->as.slots_lock); + + gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(vm->as.id), region); + return as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_LOCK); +} + static int panthor_vm_lock_region(struct panthor_vm *vm, u64 start, u64 si= ze) { struct panthor_device *ptdev =3D vm->ptdev; int ret =3D 0; =20 - /* sm_step_remap() can call panthor_vm_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) - return 0; + if (drm_WARN_ON(&ptdev->base, vm->locked_region.size)) + return -EINVAL; + + mutex_lock(&ptdev->mmu->as.slots_lock); + if (vm->as.id >=3D 0 && size) { + u64 region =3D pack_region_range(ptdev, &start, &size); + + ret =3D panthor_vm_apply_as_lock(vm, region); + } =20 - /* sm_step_remap() may need a locked region that isn't a strict superset + if (!ret) { + vm->locked_region.start =3D start; + vm->locked_region.size =3D size; + } + mutex_unlock(&ptdev->mmu->as.slots_lock); + + return ret; +} + +static int panthor_vm_expand_locked_region(struct panthor_vm *vm, + u64 start, u64 size) +{ + struct panthor_device *ptdev =3D vm->ptdev; + u64 end; + int ret =3D 0; + + /* This function is here to handle the following case: + * sm_step_remap() may need a locked region that isn't a strict superset * of the original one because of having to extend unmap boundaries beyond * it to deal with partial unmaps of transparent huge pages. What we want * in those cases is to lock the union of both regions. The new region mu= st @@ -1795,25 +1824,30 @@ 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, - 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)); + /* This function can only expand an already locked region */ + if (drm_WARN_ON(&ptdev->base, !vm->locked_region.size)) + return -EINVAL; + + /* Early out if requested range is already locked */ + if (start >=3D vm->locked_region.start && + start + size <=3D vm->locked_region.start + vm->locked_region.size) + return 0; =20 - start =3D min(start, vm->locked_region.start); - size =3D end - start; - } + end =3D max(vm->locked_region.start + vm->locked_region.size, + start + size); + + drm_WARN_ON_ONCE(&ptdev->base, (start + size <=3D vm->locked_region.start= ) || + (start >=3D vm->locked_region.start + vm->locked_region.size)); + + start =3D min(start, vm->locked_region.start); + size =3D end - start; =20 mutex_lock(&ptdev->mmu->as.slots_lock); if (vm->as.id >=3D 0 && size) { - /* Lock the region that needs to be updated */ - gpu_write64(ptdev->mmu->iomem, AS_LOCKADDR(vm->as.id), - pack_region_range(ptdev, &start, &size)); + u64 region =3D 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 panthor_vm_apply_as_lock(vm, region); } =20 if (!ret) { @@ -2367,11 +2401,14 @@ static int panthor_gpuva_sm_step_remap(struct drm_g= puva_op *op, */ unmap_hugepage_align(&op->remap, &unmap_start, &unmap_range); =20 - /* If the range changed, we might have to lock a wider region to guarant= ee - * 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. + /* If the range changed, we might have to lock a wider region to + * guarantee atomicity. */ - panthor_vm_lock_region(vm, unmap_start, unmap_range); + ret =3D panthor_vm_expand_locked_region(vm, unmap_start, + unmap_range); + if (ret) + return ret; + panthor_vm_unmap_pages(vm, unmap_start, unmap_range); } =20 --=20 2.43.0 From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7FA293ABD9F for ; Sun, 12 Jul 2026 13:55:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864502; cv=none; b=Uk1lN6mihmk0e8iZRy4XMw2sx1TzVOyxCPtduggR2n51y0iWZvO9iKOoJjpbi2OZb1mkkDI3hestId4U2eSvCuD0Yb2Tx8uJAYKkN3o2mn05h2CuynLQj0rI5VrqW34Fmrw9IHhpoiVa475A+aznSQd7FKLa0p2SaeHQhzgkCSM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864502; c=relaxed/simple; bh=Sfa99eIY5SSyQnAfwKJd49zrXjsCUleZwTF7g4fLVMc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=um+AHB7j0qNoQxeMpxiM1Qj+/huRfGvhiZ5kHPtzrUKYsoyHn9jLFEdSmyhpMtiRcmFNcmD1i8Jz3+dluYoZzp1lgyGuM33hOnk8a5TFIsNqI+3hS3RvX9lpwu3OiKu6YSkN8vILQU5oNe8BuNcwxzyUNxn+TeWy884lwHE8ljc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=QpyQfqvv; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="QpyQfqvv" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9A26A1684; Sun, 12 Jul 2026 06:54:55 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5D9863F7D8; Sun, 12 Jul 2026 06:54:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864499; bh=Sfa99eIY5SSyQnAfwKJd49zrXjsCUleZwTF7g4fLVMc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QpyQfqvvHcZgX1/Dr13cTRlByk5PNeUrVkN7XZF4smq8RhAPXsrz0O3GRdT7+n5Ie LJWrPp7VM4zfDa/Z+Q5bOwBYCif834hDPaBOUGMVwvlRVr3Oo0CgwYD2y/k+KMapaG cBzBZ2eaDWx2s8opNlZLUAjGvFTQBziJ9nG0v/SE= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 4/7] drm/panthor: Pass drm_file instead of panthor_file Date: Sun, 12 Jul 2026 15:54:36 +0200 Message-ID: <20260712135439.1546950-5-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Boris Brezillon Some sched helpers need info that are part of drm_file, and we will soon need to call drm_gem_object_lookup() from panthor_group_create(). Let's prepare for that by passing a drm_file instead of panthor_file to all current helpers taking a panthor_file, so we keep things consistent. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_drv.c | 36 +++++++++++------------- drivers/gpu/drm/panthor/panthor_mmu.c | 11 +++++--- drivers/gpu/drm/panthor/panthor_mmu.h | 6 ++-- drivers/gpu/drm/panthor/panthor_sched.c | 37 +++++++++++++++---------- drivers/gpu/drm/panthor/panthor_sched.h | 23 +++++++-------- 5 files changed, 58 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/pantho= r/panthor_drv.c index 106da676fd2ee..e18ee2d7a8e6f 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1111,7 +1111,6 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_de= vice *ddev, void *data, static int panthor_ioctl_group_submit(struct drm_device *ddev, void *data, struct drm_file *file) { - struct panthor_file *pfile =3D file->driver_priv; struct drm_panthor_group_submit *args =3D data; struct drm_panthor_queue_submit *jobs_args; struct panthor_submit_ctx ctx; @@ -1136,8 +1135,7 @@ static int panthor_ioctl_group_submit(struct drm_devi= ce *ddev, void *data, const struct drm_panthor_queue_submit *qsubmit =3D &jobs_args[i]; struct drm_sched_job *job; =20 - job =3D panthor_job_create(pfile, args->group_handle, qsubmit, - file->client_id); + job =3D panthor_job_create(file, args->group_handle, qsubmit); if (IS_ERR(job)) { ret =3D PTR_ERR(job); goto out_cleanup_submit_ctx; @@ -1217,19 +1215,17 @@ static int panthor_ioctl_group_submit(struct drm_de= vice *ddev, void *data, static int panthor_ioctl_group_destroy(struct drm_device *ddev, void *data, struct drm_file *file) { - struct panthor_file *pfile =3D file->driver_priv; struct drm_panthor_group_destroy *args =3D data; =20 if (args->pad) return -EINVAL; =20 - return panthor_group_destroy(pfile, args->group_handle); + return panthor_group_destroy(file, args->group_handle); } =20 static int panthor_ioctl_group_create(struct drm_device *ddev, void *data, struct drm_file *file) { - struct panthor_file *pfile =3D file->driver_priv; struct drm_panthor_group_create *args =3D data; struct drm_panthor_queue_create *queue_args; int ret; @@ -1245,7 +1241,7 @@ static int panthor_ioctl_group_create(struct drm_devi= ce *ddev, void *data, if (ret) goto out; =20 - ret =3D panthor_group_create(pfile, args, queue_args, file->client_id); + ret =3D panthor_group_create(file, args, queue_args); if (ret < 0) goto out; args->group_handle =3D ret; @@ -1259,10 +1255,9 @@ static int panthor_ioctl_group_create(struct drm_dev= ice *ddev, void *data, static int panthor_ioctl_group_get_state(struct drm_device *ddev, void *da= ta, struct drm_file *file) { - struct panthor_file *pfile =3D file->driver_priv; struct drm_panthor_group_get_state *args =3D data; =20 - return panthor_group_get_state(pfile, args); + return panthor_group_get_state(file, args); } =20 static int panthor_ioctl_tiler_heap_create(struct drm_device *ddev, void *= data, @@ -1605,6 +1600,7 @@ panthor_open(struct drm_device *ddev, struct drm_file= *file) if (!pfile) return -ENOMEM; =20 + file->driver_priv =3D pfile; pfile->ptdev =3D ptdev; pfile->user_mmio.offset =3D DRM_PANTHOR_USER_MMIO_OFFSET; =20 @@ -1619,19 +1615,18 @@ panthor_open(struct drm_device *ddev, struct drm_fi= le *file) #endif =20 =20 - ret =3D panthor_vm_pool_create(pfile); + ret =3D panthor_vm_pool_create(file); if (ret) goto err_free_file; =20 - ret =3D panthor_group_pool_create(pfile); + ret =3D panthor_group_pool_create(file); if (ret) goto err_destroy_vm_pool; =20 - file->driver_priv =3D pfile; return 0; =20 err_destroy_vm_pool: - panthor_vm_pool_destroy(pfile); + panthor_vm_pool_destroy(file); =20 err_free_file: kfree(pfile); @@ -1643,8 +1638,8 @@ panthor_postclose(struct drm_device *ddev, struct drm= _file *file) { struct panthor_file *pfile =3D file->driver_priv; =20 - panthor_group_pool_destroy(pfile); - panthor_vm_pool_destroy(pfile); + panthor_group_pool_destroy(file); + panthor_vm_pool_destroy(file); =20 kfree(pfile); } @@ -1704,11 +1699,13 @@ static int panthor_mmap(struct file *filp, struct v= m_area_struct *vma) } =20 static void panthor_gpu_show_fdinfo(struct panthor_device *ptdev, - struct panthor_file *pfile, + struct drm_file *file, struct drm_printer *p) { + struct panthor_file *pfile =3D file->driver_priv; + if (ptdev->profile_mask & PANTHOR_DEVICE_PROFILING_ALL) - panthor_fdinfo_gather_group_samples(pfile); + panthor_fdinfo_gather_group_samples(file); =20 if (ptdev->profile_mask & PANTHOR_DEVICE_PROFILING_TIMESTAMP) { #ifdef CONFIG_ARM_ARCH_TIMER @@ -1728,11 +1725,10 @@ static void panthor_gpu_show_fdinfo(struct panthor_= device *ptdev, static void panthor_show_internal_memory_stats(struct drm_printer *p, stru= ct drm_file *file) { char *drv_name =3D file->minor->dev->driver->name; - struct panthor_file *pfile =3D file->driver_priv; struct drm_memory_stats stats =3D {0}; =20 - panthor_fdinfo_gather_group_mem_info(pfile, &stats); - panthor_vm_heaps_sizes(pfile, &stats); + panthor_fdinfo_gather_group_mem_info(file, &stats); + panthor_vm_heaps_sizes(file, &stats); =20 drm_fdinfo_print_size(p, drv_name, "resident", "memory", stats.resident); drm_fdinfo_print_size(p, drv_name, "active", "memory", stats.active); diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index b82b01013611c..ed2ae5a6008d1 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1693,8 +1693,9 @@ panthor_vm_pool_get_vm(struct panthor_vm_pool *pool, = u32 handle) * Note that VMs can outlive the pool they were created from if other * objects hold a reference to there VMs. */ -void panthor_vm_pool_destroy(struct panthor_file *pfile) +void panthor_vm_pool_destroy(struct drm_file *file) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_vm *vm; unsigned long i; =20 @@ -1716,8 +1717,9 @@ void panthor_vm_pool_destroy(struct panthor_file *pfi= le) * * Return: 0 on success, a negative error code otherwise. */ -int panthor_vm_pool_create(struct panthor_file *pfile) +int panthor_vm_pool_create(struct drm_file *file) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_gem_object *dummy; int ret; =20 @@ -1738,7 +1740,7 @@ int panthor_vm_pool_create(struct panthor_file *pfile) return 0; =20 err_destroy_vm_pool: - panthor_vm_pool_destroy(pfile); + panthor_vm_pool_destroy(file); return ret; } =20 @@ -2186,8 +2188,9 @@ struct panthor_heap_pool *panthor_vm_get_heap_pool(st= ruct panthor_vm *vm, bool c * Calculate all heap chunk sizes in all heap pools bound to a VM. If the = VM * is active, record the size as active as well. */ -void panthor_vm_heaps_sizes(struct panthor_file *pfile, struct drm_memory_= stats *stats) +void panthor_vm_heaps_sizes(struct drm_file *file, struct drm_memory_stats= *stats) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_vm *vm; unsigned long i; =20 diff --git a/drivers/gpu/drm/panthor/panthor_mmu.h b/drivers/gpu/drm/pantho= r/panthor_mmu.h index 3522fbbce369c..e6945b6b61fc8 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.h +++ b/drivers/gpu/drm/panthor/panthor_mmu.h @@ -38,7 +38,7 @@ int panthor_vm_as(struct panthor_vm *vm); struct panthor_heap_pool * panthor_vm_get_heap_pool(struct panthor_vm *vm, bool create); =20 -void panthor_vm_heaps_sizes(struct panthor_file *pfile, struct drm_memory_= stats *stats); +void panthor_vm_heaps_sizes(struct drm_file *file, struct drm_memory_stats= *stats); =20 struct panthor_vm *panthor_vm_get(struct panthor_vm *vm); void panthor_vm_put(struct panthor_vm *vm); @@ -65,8 +65,8 @@ void panthor_vm_add_job_fence_to_bos_resvs(struct panthor= _vm *vm, struct dma_resv *panthor_vm_resv(struct panthor_vm *vm); struct drm_gem_object *panthor_vm_root_gem(struct panthor_vm *vm); =20 -void panthor_vm_pool_destroy(struct panthor_file *pfile); -int panthor_vm_pool_create(struct panthor_file *pfile); +void panthor_vm_pool_destroy(struct drm_file *file); +int panthor_vm_pool_create(struct drm_file *file); int panthor_vm_pool_create_vm(struct panthor_device *ptdev, struct panthor_vm_pool *pool, struct drm_panthor_vm_create *args); diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index 465f1b86249f8..dc77a174a3368 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3043,8 +3043,9 @@ static void update_fdinfo_stats(struct panthor_job *j= ob) } } =20 -void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile) +void panthor_fdinfo_gather_group_samples(struct drm_file *file) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_group *group; unsigned long i; @@ -3655,11 +3656,11 @@ static void add_group_kbo_sizes(struct panthor_devi= ce *ptdev, =20 #define MAX_GROUPS_PER_POOL 128 =20 -int panthor_group_create(struct panthor_file *pfile, +int panthor_group_create(struct drm_file *file, const struct drm_panthor_group_create *group_args, - const struct drm_panthor_queue_create *queue_args, - u64 drm_client_id) + const struct drm_panthor_queue_create *queue_args) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_device *ptdev =3D pfile->ptdev; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_scheduler *sched =3D ptdev->scheduler; @@ -3756,7 +3757,8 @@ int panthor_group_create(struct panthor_file *pfile, goto err_put_group; =20 for (i =3D 0; i < group_args->queues.count; i++) { - group->queues[i] =3D group_create_queue(group, &queue_args[i], drm_clien= t_id, gid, i); + group->queues[i] =3D group_create_queue(group, &queue_args[i], + file->client_id, gid, i); if (IS_ERR(group->queues[i])) { ret =3D PTR_ERR(group->queues[i]); group->queues[i] =3D NULL; @@ -3796,8 +3798,9 @@ int panthor_group_create(struct panthor_file *pfile, return ret; } =20 -int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) +int panthor_group_destroy(struct drm_file *file, u32 group_handle) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_device *ptdev =3D pfile->ptdev; struct panthor_scheduler *sched =3D ptdev->scheduler; @@ -3842,9 +3845,10 @@ static struct panthor_group *group_from_handle(struc= t panthor_group_pool *pool, return group; } =20 -int panthor_group_get_state(struct panthor_file *pfile, +int panthor_group_get_state(struct drm_file *file, struct drm_panthor_group_get_state *get_state) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_device *ptdev =3D pfile->ptdev; struct panthor_scheduler *sched =3D ptdev->scheduler; @@ -3874,8 +3878,9 @@ int panthor_group_get_state(struct panthor_file *pfil= e, return 0; } =20 -int panthor_group_pool_create(struct panthor_file *pfile) +int panthor_group_pool_create(struct drm_file *file) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool; =20 gpool =3D kzalloc_obj(*gpool); @@ -3887,8 +3892,9 @@ int panthor_group_pool_create(struct panthor_file *pf= ile) return 0; } =20 -void panthor_group_pool_destroy(struct panthor_file *pfile) +void panthor_group_pool_destroy(struct drm_file *file) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_group *group; unsigned long i; @@ -3897,7 +3903,7 @@ void panthor_group_pool_destroy(struct panthor_file *= pfile) return; =20 xa_for_each(&gpool->xa, i, group) - panthor_group_destroy(pfile, i); + panthor_group_destroy(file, i); =20 xa_destroy(&gpool->xa); kfree(gpool); @@ -3912,9 +3918,10 @@ void panthor_group_pool_destroy(struct panthor_file = *pfile) * */ void -panthor_fdinfo_gather_group_mem_info(struct panthor_file *pfile, +panthor_fdinfo_gather_group_mem_info(struct drm_file *file, struct drm_memory_stats *stats) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_group *group; unsigned long i; @@ -3977,11 +3984,11 @@ struct panthor_vm *panthor_job_vm(struct drm_sched_= job *sched_job) } =20 struct drm_sched_job * -panthor_job_create(struct panthor_file *pfile, +panthor_job_create(struct drm_file *file, u16 group_handle, - const struct drm_panthor_queue_submit *qsubmit, - u64 drm_client_id) + const struct drm_panthor_queue_submit *qsubmit) { + struct panthor_file *pfile =3D file->driver_priv; struct panthor_group_pool *gpool =3D pfile->groups; struct panthor_job *job; u32 credits; @@ -4052,7 +4059,7 @@ panthor_job_create(struct panthor_file *pfile, =20 ret =3D drm_sched_job_init(&job->base, &job->group->queues[job->queue_idx]->entity, - credits, job->group, drm_client_id); + credits, job->group, file->client_id); if (ret) goto err_put_job; =20 diff --git a/drivers/gpu/drm/panthor/panthor_sched.h b/drivers/gpu/drm/pant= hor/panthor_sched.h index 9a8692de8aded..be7e1c8b4f563 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.h +++ b/drivers/gpu/drm/panthor/panthor_sched.h @@ -15,31 +15,28 @@ struct drm_panthor_queue_create; struct drm_panthor_group_get_state; struct drm_panthor_queue_submit; struct panthor_device; -struct panthor_file; struct panthor_group_pool; struct panthor_job; =20 -int panthor_group_create(struct panthor_file *pfile, +int panthor_group_create(struct drm_file *file, const struct drm_panthor_group_create *group_args, - const struct drm_panthor_queue_create *queue_args, - u64 drm_client_id); -int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle); -int panthor_group_get_state(struct panthor_file *pfile, + const struct drm_panthor_queue_create *queue_args); +int panthor_group_destroy(struct drm_file *file, u32 group_handle); +int panthor_group_get_state(struct drm_file *file, struct drm_panthor_group_get_state *get_state); =20 struct drm_sched_job * -panthor_job_create(struct panthor_file *pfile, +panthor_job_create(struct drm_file *file, u16 group_handle, - const struct drm_panthor_queue_submit *qsubmit, - u64 drm_client_id); + const struct drm_panthor_queue_submit *qsubmit); struct drm_sched_job *panthor_job_get(struct drm_sched_job *job); struct panthor_vm *panthor_job_vm(struct drm_sched_job *sched_job); void panthor_job_put(struct drm_sched_job *job); void panthor_job_update_resvs(struct drm_exec *exec, struct drm_sched_job = *job); =20 -int panthor_group_pool_create(struct panthor_file *pfile); -void panthor_group_pool_destroy(struct panthor_file *pfile); -void panthor_fdinfo_gather_group_mem_info(struct panthor_file *pfile, +int panthor_group_pool_create(struct drm_file *file); +void panthor_group_pool_destroy(struct drm_file *file); +void panthor_fdinfo_gather_group_mem_info(struct drm_file *pfile, struct drm_memory_stats *stats); =20 int panthor_sched_init(struct panthor_device *ptdev); @@ -53,6 +50,6 @@ void panthor_sched_report_mmu_fault(struct panthor_device= *ptdev); void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev= ); void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 even= ts); =20 -void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile); +void panthor_fdinfo_gather_group_samples(struct drm_file *file); =20 #endif --=20 2.43.0 From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 670513ACA6A for ; Sun, 12 Jul 2026 13:55:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864505; cv=none; b=CVqnHPpAbloPJxaPIfRB353W+4KCGAI5a8IYKZ8nW05lTU0X39VS3iWxfbVV/4EWn3T66CpWkEWst6mOnFnIwWPafbaySCQEkGQnPmVNtholRqV76XpKpPXftC/kTCAxZLJfhwVpDj7Ur40oqAkwn8IAbiZQCf2Y7jo6n+6gcY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864505; c=relaxed/simple; bh=BHBRdDyZsgGf3EjWM4xIGTLZE0SyBofZQ7alSwO1G9Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LJsoVA7m68t4re2QAAa5f7Kpv+y7KjUZUk7zKHnlOGGIRMJ7Y0YwPxeCfRQNFOnMmsM/QBO1WVq29fYEH5mNC3VLyRfETY5TqIOukYnzJ5WVAm60YLDNUYgOmsuhEYbdWV+387guYzcyJVgDVPsC3/v2UxYynedX516HjaviYio= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=Th/BurNM; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="Th/BurNM" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 8B8071688; Sun, 12 Jul 2026 06:54:58 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4E9E83F7D8; Sun, 12 Jul 2026 06:55:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864502; bh=BHBRdDyZsgGf3EjWM4xIGTLZE0SyBofZQ7alSwO1G9Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Th/BurNMFudU+nbSDtGLhH4Ontmh6OVDUBBUVQ9CS5YjRLNNvG9Jp7iMP+yypDGOF RYuhIVQXU8dL+QkWGYUHuO1IuUSUenoittb2XT5Sj8MWPEruuyB5izrI0K5gTYKqnK 9cu8lqVfdAHipl1KAsulcg6i9v8BrrGtRf0UAGCk= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Ketil Johnsen Subject: [PATCH v2 5/7] drm/panthor: Don't allocate protm_suspend_buf Date: Sun, 12 Jul 2026 15:54:37 +0200 Message-ID: <20260712135439.1546950-6-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The PROTM suspend buffer is only needed if the group is going to use PROTM in the first place, so let's not assume we need one until we're being asked to. Signed-off-by: Ketil Johnsen Reviewed-by: Boris Brezillon Reviewed-by: Steven Price --- drivers/gpu/drm/panthor/panthor_sched.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index dc77a174a3368..86c0f12b09e11 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3642,9 +3642,11 @@ static void add_group_kbo_sizes(struct panthor_devic= e *ptdev, if (drm_WARN_ON(&ptdev->base, ptdev !=3D group->ptdev)) return; =20 - group->fdinfo.kbo_sizes +=3D group->suspend_buf->obj->size; - group->fdinfo.kbo_sizes +=3D group->protm_suspend_buf->obj->size; group->fdinfo.kbo_sizes +=3D group->syncobjs->obj->size; + group->fdinfo.kbo_sizes +=3D group->suspend_buf->obj->size; + + if (group->protm_suspend_buf) + group->fdinfo.kbo_sizes +=3D group->protm_suspend_buf->obj->size; =20 for (i =3D 0; i < group->queue_count; i++) { queue =3D group->queues[i]; @@ -3724,14 +3726,6 @@ int panthor_group_create(struct drm_file *file, goto err_put_group; } =20 - suspend_size =3D csg_iface->control->protm_suspend_size; - group->protm_suspend_buf =3D panthor_fw_alloc_suspend_buf_mem(ptdev, susp= end_size); - if (IS_ERR(group->protm_suspend_buf)) { - ret =3D PTR_ERR(group->protm_suspend_buf); - group->protm_suspend_buf =3D NULL; - goto err_put_group; - } - group->syncobjs =3D panthor_kernel_bo_create(ptdev, group->vm, group_args->queues.count * sizeof(struct panthor_syncobj_64b), --=20 2.43.0 From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E5E3E3AD51C for ; Sun, 12 Jul 2026 13:55:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864509; cv=none; b=EeQ5k4LwdiJONVrvnbwihex0Mr1zZt2RgMeTxiJTKz+/4HJTnThpKOba06UvkxTBPlvGduidIM3iJBKMrQ+TTaL8tjUkmStdbCYiPr7lG1RfgV3Ozf8Bb3UOBMQzAU4gzisdM+2a/UOP9zedQvCBpLdahg0yoS25dh11DT86B3E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864509; c=relaxed/simple; bh=SuAGa9RdvYtLYejjWCIFCFM2nkX4livSCeWV2Mg3d8I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rAvkm7HGAIOeYKGOZwsap77NhPPB6Btyms3SDU2jRihNOfOloD38PVYKtH+xPXKexsL5r6DhbKzR8X/nmMpA0YJrA8B5qiF3NhDA7yvVzDIxN5sM+5CtZF3FhHP0KBSFd5yKdhmZVXuShFExWucf6KIHMoGev5BvrgBPs3r/fis= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=neYk2q+f; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="neYk2q+f" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 361AC1684; Sun, 12 Jul 2026 06:55:02 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 42ADD3F7D8; Sun, 12 Jul 2026 06:55:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864506; bh=SuAGa9RdvYtLYejjWCIFCFM2nkX4livSCeWV2Mg3d8I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=neYk2q+fREij7y7U7wJGn9+qWQv3vMfDWnQ0yG3eba4pK3JoExo61Vt06QYh1h3Fj VjPN8XzLAOIv/XfpdquMugySHWR9f/sdivA0EiUbZUURyWctS6RhvQHLqbflryeapN WqlPL97yGO8UIrvrMr1gtKSBeacfVLEj51NMAVCQ= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Florent Tomasin , Paul Toadere , Samuel Percival , Ketil Johnsen Subject: [PATCH v2 6/7] drm/panthor: Add support for entering and exiting protected mode Date: Sun, 12 Jul 2026 15:54:38 +0200 Message-ID: <20260712135439.1546950-7-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Florent Tomasin This patch modifies the Panthor driver code to allow handling of the GPU HW protected mode enter and exit. The logic added by this patch includes: - the mechanisms needed for entering and exiting protected mode. - the handling of protected mode IRQs and FW interactions. - the scheduler changes needed to decide when to enter protected mode based on CSG scheduling. - GPU fault handling during protected mode execution. Note that the submission of a protected mode jobs are done from the user space. The following is a summary of how protected mode is entered and exited: - When the GPU detects a protected mode job needs to be executed, an IRQ is sent to the CPU to notify the kernel driver that the job is blocked until the GPU has entered protected mode. The entering of protected mode is controlled by the kernel driver. - The Mali Panthor CSF driver will schedule a tick and evaluate which CS in the CSG to schedule on slot needs protected mode. If the priority of the CSG is not sufficiently high, the protected mode job will not progress until the CSG is scheduled at top priority. - The Panthor scheduler notifies the GPU that the blocked protected jobs will soon be able to progress. - Once all CSG and CS slots are updated, the scheduler requests the GPU to enter protected mode and waits for it to be acknowledged. - If successful, all protected mode jobs will resume execution while normal mode jobs block until the GPU exits protected mode, or the kernel driver rotates the CSGs and forces the GPU to exit protected mode. - If unsuccessful, the scheduler will request a GPU reset. - Faults during protected mode are reported GPU wide, and not as CSG/CS errors. We allow only one CSG to run in protected mode at a time so we know which CSG to blame for the fault. - All faults during protected mode are handled with a GPU reset. - When a protected mode job is suspended as a result of the CSGs rotation, the GPU will send an IRQ to the CPU to notify that the protected mode job needs to resume. This sequence will continue so long the user space is submitting protected mode jobs. Signed-off-by: Florent Tomasin Co-developed-by: Paul Toadere Signed-off-by: Paul Toadere Co-developed-by: Samuel Percival Signed-off-by: Samuel Percival Co-developed-by: Ketil Johnsen Signed-off-by: Ketil Johnsen --- drivers/gpu/drm/panthor/panthor_device.c | 1 + drivers/gpu/drm/panthor/panthor_device.h | 33 +++ drivers/gpu/drm/panthor/panthor_fw.c | 90 +++++- drivers/gpu/drm/panthor/panthor_fw.h | 5 + drivers/gpu/drm/panthor/panthor_gpu.c | 53 +++- drivers/gpu/drm/panthor/panthor_gpu.h | 4 + drivers/gpu/drm/panthor/panthor_mmu.c | 29 +- drivers/gpu/drm/panthor/panthor_sched.c | 333 ++++++++++++++++++++++- drivers/gpu/drm/panthor/panthor_sched.h | 4 + 9 files changed, 533 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/pan= thor/panthor_device.c index bd417d6ae8c00..c0cdefd330799 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -172,6 +172,7 @@ int panthor_device_init(struct panthor_device *ptdev) =20 ptdev->soc_data =3D of_device_get_match_data(ptdev->base.dev); =20 + init_rwsem(&ptdev->protm.lock); init_completion(&ptdev->unplug.done); ret =3D drmm_mutex_init(&ptdev->base, &ptdev->unplug.lock); if (ret) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/pan= thor/panthor_device.h index 35679bfa1f3a6..e5df42f095717 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -332,6 +332,26 @@ struct panthor_device { struct list_head node; } gems; #endif + /** @protm: Protected mode related data. */ + struct { + /** + * @lock: Lock to prevent MMU operations during protected mode. + * + * The MMU HW will silently ignore commands issued when the + * GPU is in protected mode. It is important that we handle this + * for some of the MMU HW interactions. + * + * panthor_vm_lock_region() will down this as a reader, and + * this will prevent any new transition into protected mode. + * panthor_vm_lock_region() will then wait for GPU to return + * to normal mode before proceeding. + * It is now safe to carry out page table modifications. + * Only the switch into protected mode itself will down this + * as a writer. The wait for GPU to leave protected mode + * in panthor_vm_lock_region() will ensure this is enough. + */ + struct rw_semaphore lock; + } protm; }; =20 struct panthor_gpu_usage { @@ -628,6 +648,19 @@ static inline void panthor_ ## __name ## _irq_disable_= events(struct panthor_irq gpu_write(pirq->iomem, INT_MASK, pirq->mask); \ } =20 +/** + * PANTHOR_IRQ_HANDLER_DECL() - Forward declare interrupt handlers helpers + * + * Exposes the IRQ helper functions panthor_xxx_irq_enable_events() and + * panthor_xxx_disable_events(), so these can be used from within the + * IRQ handler itself. + */ +#define PANTHOR_IRQ_HANDLER_DECL(__name) \ +static inline void panthor_ ## __name ## _irq_enable_events( \ + struct panthor_irq *pirq, u32 mask); \ +static inline void panthor_ ## __name ## _irq_disable_events( \ + struct panthor_irq *pirq, u32 mask); + extern struct workqueue_struct *panthor_cleanup_wq; =20 static inline void gpu_write(void __iomem *iomem, u32 reg, u32 data) diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor= /panthor_fw.c index 389f9182fac16..76792f9175b57 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1035,7 +1035,9 @@ static void panthor_fw_init_global_iface(struct panth= or_device *ptdev) GLB_CFG_PROGRESS_TIMER | GLB_CFG_POWEROFF_TIMER | GLB_IDLE_EN | - GLB_IDLE; + GLB_IDLE | + GLB_PROTM_ENTER | + GLB_PROTM_EXIT; =20 if (panthor_fw_has_glb_state(ptdev)) glb_iface->input->ack_irq_mask |=3D GLB_STATE_MASK; @@ -1441,6 +1443,92 @@ static void panthor_fw_ping_work(struct work_struct = *work) } } =20 +static int panthor_fw_protm_enter_wait(struct panthor_device *ptdev, + u32 timeout_ms) +{ + struct panthor_fw_global_iface *glb_iface =3D + panthor_fw_get_glb_iface(ptdev); + int ret; + + /* Poll for the entry of protected mode. + * GLB_PROTM_EXIT is also checked as it may happen that FW enters and + * exits protected mode very quickly and so the GPU_STATUS_PROTM_ACTIVE + * bit is seen as 0 throughout the polling. + */ + ret =3D wait_event_timeout(ptdev->fw->req_waitqueue, + (panthor_gpu_status(ptdev) & + GPU_STATUS_PROTM_ACTIVE) || + ((glb_iface->input->req ^ glb_iface->output->ack) & + GLB_PROTM_EXIT), + msecs_to_jiffies(timeout_ms)); + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +int panthor_fw_protm_enter(struct panthor_device *ptdev) +{ + struct panthor_fw_global_iface *glb_iface =3D + panthor_fw_get_glb_iface(ptdev); + u32 acked; + int ret; + + /* Restart the watchdog timer, so it doesn't hit immediately + * after entering protected mode, since this will cause GPU + * to exit protected mode to respond to the ping request. + */ + mod_delayed_work(ptdev->reset.wq, &ptdev->fw->watchdog.ping_work, + msecs_to_jiffies(PING_INTERVAL_MS)); + + panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PROTM_ENTER); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); + + ret =3D panthor_fw_glb_wait_acks(ptdev, GLB_PROTM_ENTER, &acked, 4000); + if (ret) { + drm_err(&ptdev->base, + "Wait for FW protected mode acknowledge timed out"); + return ret; + } + + /* Wait for the GPU to actually enter protected mode. + * There would be some time gap between FW sending the + * ACK for GLB_PROTM_ENTER and GPU entering protected mode. + */ + ret =3D panthor_fw_protm_enter_wait(ptdev, 500); + if (ret) + drm_err(&ptdev->base, + "Wait for GPU protected mode enter timed out"); + + return ret; +} + +int panthor_fw_protm_exit_wait(struct panthor_device *ptdev, u32 timeout_m= s) +{ + int ret; + + ret =3D wait_event_timeout(ptdev->fw->req_waitqueue, + !(panthor_gpu_status(ptdev) & + GPU_STATUS_PROTM_ACTIVE), + msecs_to_jiffies(timeout_ms)); + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +int panthor_fw_protm_exit(struct panthor_device *ptdev) +{ + struct panthor_fw_global_iface *glb_iface =3D + panthor_fw_get_glb_iface(ptdev); + + /* Send PING request to force an exit */ + panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PING); + panthor_fw_ring_doorbell(ptdev, CSF_GLB_DOORBELL_ID); + + return panthor_fw_protm_exit_wait(ptdev, 500); +} + /** * panthor_fw_init() - Initialize FW related data. * @ptdev: Device. diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor= /panthor_fw.h index a99a9b6f4825c..78658d64b807e 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.h +++ b/drivers/gpu/drm/panthor/panthor_fw.h @@ -529,4 +529,9 @@ static inline int panthor_fw_resume(struct panthor_devi= ce *ptdev) int panthor_fw_init(struct panthor_device *ptdev); void panthor_fw_unplug(struct panthor_device *ptdev); =20 +int panthor_fw_protm_enter(struct panthor_device *ptdev); +int panthor_fw_protm_exit(struct panthor_device *ptdev); +int panthor_fw_protm_exit_wait(struct panthor_device *ptdev, + u32 timeout_ms); + #endif diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/pantho= r/panthor_gpu.c index e52c5675981f5..9054ac251fd3e 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -46,6 +46,9 @@ struct panthor_gpu { =20 /** @cache_flush_lock: Lock to serialize cache flushes */ struct mutex cache_flush_lock; + + /** @protm_fault: True if a GPU_IRQ_PROTM_FAULT has been raised */ + bool protm_fault; }; =20 #define GPU_INTERRUPTS_MASK \ @@ -86,10 +89,42 @@ static void panthor_gpu_l2_config_set(struct panthor_de= vice *ptdev) gpu_write(gpu->iomem, GPU_L2_CONFIG, l2_config); } =20 +PANTHOR_IRQ_HANDLER_DECL(gpu); + static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 stat= us) { struct panthor_gpu *gpu =3D ptdev->gpu; =20 + if (status & GPU_IRQ_PROTM_FAULT) { + /* Make a note of this fault before we clear the interrupt. + * This ensures panthor_gpu_protm_fault_pending() can always + * give an accurate answer. + * + * There is a race we need to handle between two interrupts, + * this GPU_IRQ_PROTM_FAULT and JOB_INT_GLOBAL_IF with the + * GLB_PROTM_EXIT event. + * + * Although GPU_IRQ_PROTM_FAULT is always raised first, + * processing of GLB_PROTM_EXIT could still execute first. + * The handling of GLB_PROTM_EXIT MUST know if a + * GPU_IRQ_PROTM_FAULT has been raised or not, otherwise it + * could incorrectly think everything is fine and resume + * with normal scheduling to early. + * + * We still need to do fault handling (reset) here as well, + * because some failures during protected mode do not + * automatically exit protected mode (no GLB_PROTM_EXIT). + * This means there is a slim chance we do two GPU resets + * instead of just one. This is not ideal, but should be safe. + */ + WRITE_ONCE(gpu->protm_fault, true); + + drm_warn(&ptdev->base, "GPU Fault in protected mode\n"); + panthor_gpu_irq_disable_events(&ptdev->gpu->irq, + GPU_IRQ_PROTM_FAULT); + panthor_device_schedule_reset(ptdev); + } + gpu_write(gpu->irq.iomem, INT_CLEAR, status); =20 if (tracepoint_enabled(gpu_power_status) && (status & GPU_POWER_INTERRUPT= S_MASK)) @@ -106,8 +141,6 @@ static void panthor_gpu_irq_handler(struct panthor_devi= ce *ptdev, u32 status) fault_status, panthor_exception_name(ptdev, fault_status & 0xFF), address); } - if (status & GPU_IRQ_PROTM_FAULT) - drm_warn(&ptdev->base, "GPU Fault in protected mode\n"); =20 spin_lock(&ptdev->gpu->reqs_lock); if (status & ptdev->gpu->pending_reqs) { @@ -118,6 +151,13 @@ static void panthor_gpu_irq_handler(struct panthor_dev= ice *ptdev, u32 status) } PANTHOR_IRQ_HANDLER(gpu, panthor_gpu_irq_handler); =20 +bool panthor_gpu_protm_fault_pending(struct panthor_device *ptdev) +{ + return READ_ONCE(ptdev->gpu->protm_fault) || + gpu_read(ptdev->gpu->irq.iomem, INT_RAWSTAT) & + GPU_IRQ_PROTM_FAULT; +} + /** * panthor_gpu_unplug() - Called when the GPU is unplugged. * @ptdev: Device to unplug. @@ -380,6 +420,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptde= v) unsigned long flags; =20 spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); + + WRITE_ONCE(ptdev->gpu->protm_fault, false); + panthor_gpu_irq_enable_events(&ptdev->gpu->irq, GPU_IRQ_PROTM_FAULT); + if (!drm_WARN_ON(&ptdev->base, ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) { ptdev->gpu->pending_reqs |=3D GPU_IRQ_RESET_COMPLETED; @@ -480,3 +524,8 @@ int panthor_gpu_coherency_init(struct panthor_device *p= tdev) drm_err(&ptdev->base, "Coherency not supported by the device"); return -ENOTSUPP; } + +u32 panthor_gpu_status(struct panthor_device *ptdev) +{ + return gpu_read(ptdev->gpu->iomem, GPU_STATUS); +} diff --git a/drivers/gpu/drm/panthor/panthor_gpu.h b/drivers/gpu/drm/pantho= r/panthor_gpu.h index f615feb056094..00ec9a8c5d7fd 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.h +++ b/drivers/gpu/drm/panthor/panthor_gpu.h @@ -60,4 +60,8 @@ u64 panthor_gpu_get_cycle_count(struct panthor_device *pt= dev); =20 int panthor_gpu_coherency_init(struct panthor_device *ptdev); =20 +u32 panthor_gpu_status(struct panthor_device *ptdev); + +bool panthor_gpu_protm_fault_pending(struct panthor_device *ptdev); + #endif diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/pantho= r/panthor_mmu.c index ed2ae5a6008d1..75c484118f6ba 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1794,11 +1794,30 @@ static int panthor_vm_lock_region(struct panthor_vm= *vm, u64 start, u64 size) if (drm_WARN_ON(&ptdev->base, vm->locked_region.size)) return -EINVAL; =20 + /* Prevent GPU from entering protected mode */ + panthor_sched_protm_block(ptdev); + mutex_lock(&ptdev->mmu->as.slots_lock); if (vm->as.id >=3D 0 && size) { - u64 region =3D pack_region_range(ptdev, &start, &size); + mutex_unlock(&ptdev->mmu->as.slots_lock); =20 - ret =3D panthor_vm_apply_as_lock(vm, region); + /* Wait for GPU to exit protected mode. + * There is a slim chance that the GPU has faulted in protected + * mode. Such failures are handled with a GPU reset. + * That is why we temporary release the as.slots_lock, while we + * wait for protected mode to exit, since the same lock will + * be acquired during the GPU reset procedure. + */ + + panthor_sched_protm_exit(ptdev); + + mutex_lock(&ptdev->mmu->as.slots_lock); + + if (vm->as.id >=3D 0 && size) { + u64 region =3D pack_region_range(ptdev, &start, &size); + + ret =3D panthor_vm_apply_as_lock(vm, region); + } } =20 if (!ret) { @@ -1807,6 +1826,9 @@ static int panthor_vm_lock_region(struct panthor_vm *= vm, u64 start, u64 size) } mutex_unlock(&ptdev->mmu->as.slots_lock); =20 + if (ret) + panthor_sched_protm_unblock(ptdev); + return ret; } =20 @@ -1890,6 +1912,9 @@ static void panthor_vm_unlock_region(struct panthor_v= m *vm) vm->locked_region.start =3D 0; vm->locked_region.size =3D 0; mutex_unlock(&ptdev->mmu->as.slots_lock); + + /* Let scheduler know it is safe to enter protected mode again */ + panthor_sched_protm_unblock(ptdev); } =20 static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 stat= us) diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index 86c0f12b09e11..efa53b0a05d38 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -309,6 +309,17 @@ struct panthor_scheduler { */ struct list_head stopped_groups; } reset; + + /** @protm: Protected mode related fields. */ + struct { + /** + * @active_group: The active protected group. + * + * We only allow one protected group to run at the same time, + * as it makes it easier to handle faults in protected mode. + */ + struct panthor_group *active_group; + } protm; }; =20 /** @@ -571,6 +582,16 @@ struct panthor_group { /** @fatal_queues: Bitmask reflecting the queues that hit a fatal excepti= on. */ u32 fatal_queues; =20 + /** + * @protm_pending_queues: Bitmask reflecting the queues that have raised + * a CS_PROTM_PENDING. + * + * The GPU will set the bit associated to the queue pending protected + * mode when a PROT_REGION command is executing or when trying to resume + * previously suspended protected mode jobs. + */ + u32 protm_pending_queues; + /** @tiler_oom: Mask of queues that have a tiler OOM event to process. */ atomic_t tiler_oom; =20 @@ -1054,6 +1075,7 @@ group_unbind_locked(struct panthor_group *group) slot =3D &ptdev->scheduler->csg_slots[group->csg_id]; panthor_vm_idle(group->vm); group->csg_id =3D -1; + group->protm_pending_queues =3D 0; =20 /* Tiler OOM events will be re-issued next time the group is scheduled. */ atomic_set(&group->tiler_oom, 0); @@ -1473,6 +1495,27 @@ csg_slot_prog_locked(struct panthor_device *ptdev, u= 32 csg_id, u32 priority) return 0; } =20 +static void +cs_slot_process_protm_pending_event_locked(struct panthor_device *ptdev, + u32 csg_id, u32 cs_id) +{ + struct panthor_scheduler *sched =3D ptdev->scheduler; + struct panthor_csg_slot *csg_slot =3D &sched->csg_slots[csg_id]; + struct panthor_group *group =3D csg_slot->group; + + lockdep_assert_held(&sched->lock); + + if (!group) + return; + + /* Do not allow user space work to switch into protected mode, as we + * do not fully support this quite yet. + */ + group->fatal_queues |=3D BIT(cs_id); + + sched_queue_delayed_work(sched, tick, 0); +} + static void cs_slot_process_fatal_event_locked(struct panthor_device *ptdev, u32 csg_id, u32 cs_id) @@ -1719,6 +1762,9 @@ static bool cs_slot_process_irq_locked(struct panthor= _device *ptdev, if (events & CS_TILER_OOM) cs_slot_process_tiler_oom_event_locked(ptdev, csg_id, cs_id); =20 + if (events & CS_PROTM_PENDING) + cs_slot_process_protm_pending_event_locked(ptdev, csg_id, cs_id); + /* We don't acknowledge the TILER_OOM event since its handling is * deferred to a separate work. */ @@ -1849,6 +1895,34 @@ static void sched_process_idle_event_locked(struct p= anthor_device *ptdev) sched_queue_delayed_work(ptdev->scheduler, tick, 0); } =20 +static void sched_process_protm_exit_event_locked(struct panthor_device *p= tdev) +{ + struct panthor_fw_global_iface *glb_iface =3D panthor_fw_get_glb_iface(pt= dev); + struct panthor_scheduler *sched =3D ptdev->scheduler; + + lockdep_assert_held(&sched->lock); + + /* Acknowledge the protm exit */ + panthor_fw_update_reqs(glb_iface, req, glb_iface->output->ack, + GLB_PROTM_EXIT); + + /* If there are pending fault from protected mode execution, then early + * out here. The GPU_IRQ_PROTM_FAULT handling will trigger the propper + * error recovery via a GPU reset. + */ + if (panthor_gpu_protm_fault_pending(ptdev)) + return; + + /* Protected mode exited successfully. Clear protm.active_group so that + * tick_work() is unblocked to schedule new work. + */ + + group_put(sched->protm.active_group); + sched->protm.active_group =3D NULL; + + sched_queue_delayed_work(sched, tick, 0); +} + /** * sched_process_global_irq_locked() - Process the scheduling part of a gl= obal IRQ * @ptdev: Device. @@ -1864,6 +1938,9 @@ static void sched_process_global_irq_locked(struct pa= nthor_device *ptdev) ack =3D READ_ONCE(glb_iface->output->ack); evts =3D (req ^ ack) & GLB_EVT_MASK; =20 + if (evts & GLB_PROTM_EXIT) + sched_process_protm_exit_event_locked(ptdev); + if (evts & GLB_IDLE) sched_process_idle_event_locked(ptdev); } @@ -1873,23 +1950,87 @@ static void process_fw_events_work(struct work_stru= ct *work) struct panthor_scheduler *sched =3D container_of(work, struct panthor_sch= eduler, fw_events_work); u32 events =3D atomic_xchg(&sched->fw_events, 0); + u32 csg_events =3D events & ~JOB_INT_GLOBAL_IF; struct panthor_device *ptdev =3D sched->ptdev; =20 mutex_lock(&sched->lock); =20 + while (csg_events) { + u32 csg_id =3D ffs(csg_events) - 1; + + sched_process_csg_irq_locked(ptdev, csg_id); + csg_events &=3D ~BIT(csg_id); + } + if (events & JOB_INT_GLOBAL_IF) { sched_process_global_irq_locked(ptdev); events &=3D ~JOB_INT_GLOBAL_IF; } =20 - while (events) { - u32 csg_id =3D ffs(events) - 1; + mutex_unlock(&sched->lock); +} =20 - sched_process_csg_irq_locked(ptdev, csg_id); - events &=3D ~BIT(csg_id); - } +static void handle_protm_fault(struct panthor_device *ptdev) +{ + struct panthor_scheduler *sched =3D ptdev->scheduler; + u32 csg_id; + struct panthor_group *protm_group; =20 - mutex_unlock(&sched->lock); + guard(mutex)(&sched->lock); + + protm_group =3D sched->protm.active_group; + + if (!protm_group || !panthor_gpu_protm_fault_pending(ptdev)) + return; + + protm_group->fatal_queues |=3D GENMASK(protm_group->queue_count - 1, 0); + + /* Different kinds of faults during protected mode can give different + * behavior/state. + * Case 1) The fault keeps the GPU in protected mode. + * In this case, the request to exit protected mode below will + * fail and we need to take some further action. + * Case 2) The fault do not keep the GPU in protected mode. + * In this case, the request to exit protected + * mode below will succeed, and we don't need to take any + * further action right here. + */ + if (!panthor_fw_protm_exit(ptdev)) + return; + + /* GPU failed to exit protected mode. + * Mark all CSGs as suspended and unbind them, so that they are + * unaffected by the GPU reset itself. + * We can not suspend the groups in this case, because we are stuck + * in protected mode. That is also the reason it is safe to unbind + * without suspending first (the groups are already "suspended"). + * The failing protected group will be scheduled for termination. + */ + + for (csg_id =3D 0; csg_id < sched->csg_slot_count; csg_id++) { + struct panthor_group *group =3D sched->csg_slots[csg_id].group; + + if (!group) + continue; + + group_get(group); + + group->state =3D PANTHOR_CS_GROUP_SUSPENDED; + sched_process_csg_irq_locked(ptdev, group->csg_id); + group_unbind_locked(group); + + drm_WARN_ON(&group->ptdev->base, !list_empty(&group->run_node)); + + if (group_can_run(group)) { + list_add(&group->run_node, + &sched->groups.idle[group->priority]); + } else { + list_del_init(&group->wait_node); + group_queue_work(group, term); + } + + group_put(group); + } } =20 /** @@ -1935,6 +2076,12 @@ static void csgs_upd_ctx_init(struct panthor_csg_slo= ts_upd_ctx *ctx) memset(ctx, 0, sizeof(*ctx)); } =20 +static void csgs_upd_ctx_ring_doorbell(struct panthor_csg_slots_upd_ctx *c= tx, + u32 csg_id) +{ + ctx->update_mask |=3D BIT(csg_id); +} + static void csgs_upd_ctx_queue_reqs(struct panthor_device *ptdev, struct panthor_csg_slots_upd_ctx *ctx, u32 csg_id, u32 value, u32 mask) @@ -1945,7 +2092,8 @@ static void csgs_upd_ctx_queue_reqs(struct panthor_de= vice *ptdev, =20 ctx->requests[csg_id].value =3D (ctx->requests[csg_id].value & ~mask) | (= value & mask); ctx->requests[csg_id].mask |=3D mask; - ctx->update_mask |=3D BIT(csg_id); + + csgs_upd_ctx_ring_doorbell(ctx, csg_id); } =20 static int csgs_upd_ctx_apply_locked(struct panthor_device *ptdev, @@ -1962,8 +2110,12 @@ static int csgs_upd_ctx_apply_locked(struct panthor_= device *ptdev, while (update_slots) { struct panthor_fw_csg_iface *csg_iface; u32 csg_id =3D ffs(update_slots) - 1; + u32 req_mask =3D ctx->requests[csg_id].mask; =20 update_slots &=3D ~BIT(csg_id); + if (!req_mask) + continue; + csg_iface =3D panthor_fw_get_csg_iface(ptdev, csg_id); panthor_fw_update_reqs(csg_iface, req, ctx->requests[csg_id].value, @@ -1980,6 +2132,9 @@ static int csgs_upd_ctx_apply_locked(struct panthor_d= evice *ptdev, int ret; =20 update_slots &=3D ~BIT(csg_id); + if (!req_mask) + continue; + csg_iface =3D panthor_fw_get_csg_iface(ptdev, csg_id); =20 ret =3D panthor_fw_csg_wait_acks(ptdev, csg_id, req_mask, &acked, 100); @@ -2016,6 +2171,7 @@ struct panthor_sched_tick_ctx { bool immediate_tick; bool stop_tick; u32 csg_upd_failed_mask; + struct panthor_group *protm_group; }; =20 static bool @@ -2057,6 +2213,10 @@ tick_ctx_pick_groups_from_list(const struct panthor_= scheduler *sched, if (!owned_by_tick_ctx) group_get(group); =20 + /* Only the first pick is allowed to request switch to protm */ + if (ctx->group_count =3D=3D 0 && group->protm_pending_queues) + ctx->protm_group =3D group; + ctx->group_count++; =20 /* If we have more than one active group with the same priority, @@ -2214,6 +2374,48 @@ static void group_term_work(struct work_struct *work) group_put(group); } =20 +static int panthor_sched_protm_enter(struct panthor_device *ptdev) +{ + struct panthor_scheduler *sched =3D ptdev->scheduler; + int ret; + + lockdep_assert_held(&sched->lock); + + if (drm_WARN_ON(&ptdev->base, sched->protm.active_group)) + return 0; + + down_write(&ptdev->protm.lock); + ret =3D panthor_fw_protm_enter(ptdev); + up_write(&ptdev->protm.lock); + + return ret; +} + +void panthor_sched_protm_block(struct panthor_device *ptdev) +{ + down_read(&ptdev->protm.lock); +} + +void panthor_sched_protm_unblock(struct panthor_device *ptdev) +{ + up_read(&ptdev->protm.lock); +} + +int panthor_sched_protm_exit(struct panthor_device *ptdev) +{ + int ret; + + /* First, wait a little bit for FW to exit protected mode on its own. + * Only if that fails do we request a protected mode exit. + */ + + ret =3D panthor_fw_protm_exit_wait(ptdev, 5); + if (ret) + ret =3D panthor_fw_protm_exit(ptdev); + + return ret; +} + static void tick_ctx_cleanup(struct panthor_scheduler *sched, struct panthor_sched_tick_ctx *ctx) @@ -2331,6 +2533,46 @@ tick_ctx_schedule_group(struct panthor_scheduler *sc= hed, CSG_ENDPOINT_CONFIG); } =20 +static void +tick_ctx_handle_protm_group(struct panthor_scheduler *sched, + struct panthor_csg_slots_upd_ctx *upd_ctx, + struct panthor_group *group) +{ + struct panthor_device *ptdev =3D sched->ptdev; + struct panthor_fw_csg_iface *csg_iface; + u32 q; + + if (drm_WARN_ON(&ptdev->base, group->csg_id < 0)) + return; + + csg_iface =3D panthor_fw_get_csg_iface(ptdev, group->csg_id); + + if (!group->protm_pending_queues) + return; + + for (q =3D 0; q < group->queue_count; q++) { + struct panthor_fw_cs_iface *cs_iface; + + if (!(group->protm_pending_queues & BIT(q))) + continue; + + cs_iface =3D panthor_fw_get_cs_iface(ptdev, group->csg_id, q); + + /* Ack any pending CS_PROTM_PENDING so it can run in protm */ + if ((cs_iface->output->ack ^ cs_iface->input->req) & + CS_PROTM_PENDING) { + panthor_fw_update_reqs(cs_iface, req, + cs_iface->output->ack, + CS_PROTM_PENDING); + group->protm_pending_queues &=3D ~BIT(q); + } + } + + panthor_fw_toggle_reqs(csg_iface, doorbell_req, doorbell_ack, + group->protm_pending_queues); + csgs_upd_ctx_ring_doorbell(upd_ctx, group->csg_id); +} + static void tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_= ctx *ctx) { @@ -2403,6 +2645,9 @@ tick_ctx_apply(struct panthor_scheduler *sched, struc= t panthor_sched_tick_ctx *c } } =20 + if (ctx->protm_group) + tick_ctx_handle_protm_group(sched, &upd_ctx, ctx->protm_group); + ret =3D csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); if (ret) { panthor_device_schedule_reset(ptdev); @@ -2443,6 +2688,20 @@ tick_ctx_apply(struct panthor_scheduler *sched, stru= ct panthor_sched_tick_ctx *c =20 sched->used_csg_slot_count =3D ctx->group_count; sched->might_have_idle_groups =3D ctx->idle_group_count > 0; + + if (ctx->protm_group) { + ret =3D panthor_sched_protm_enter(ptdev); + if (ret) { + panthor_device_schedule_reset(ptdev); + ctx->csg_upd_failed_mask =3D U32_MAX; + } + + if (drm_WARN_ON(&ptdev->base, sched->protm.active_group)) + group_put(sched->protm.active_group); + + sched->protm.active_group =3D ctx->protm_group; + group_get(sched->protm.active_group); + } } =20 static u64 @@ -2499,6 +2758,26 @@ static void tick_work(struct work_struct *work) if (panthor_device_reset_is_pending(sched->ptdev)) goto out_unlock; =20 + if (sched->protm.active_group) { + bool rt_groups_waiting =3D + !list_empty(&sched->groups.runnable[PANTHOR_CSG_PRIORITY_RT]); + + if (full_tick || rt_groups_waiting) { + /* We allow preemption in this case, but we must + * ensure we are fully out of protected mode first. + * We rely on the GLB_PROTM_EXIT (or error recovery) + * to get a new tick. + */ + if (panthor_fw_protm_exit(ptdev)) { + drm_err(&ptdev->base, + "Failed to exit protected mode"); + panthor_device_schedule_reset(ptdev); + } + } + + goto out_unlock; + } + tick_ctx_init(sched, &ctx); if (ctx.csg_upd_failed_mask) goto out_cleanup_ctx; @@ -2551,13 +2830,34 @@ static void tick_work(struct work_struct *work) } =20 /* If we have free CSG slots left, pick idle groups */ - for (prio =3D PANTHOR_CSG_PRIORITY_COUNT - 1; - prio >=3D 0 && !tick_ctx_is_full(sched, &ctx); - prio--) { - /* Check the old_group queue first to avoid reprogramming the slots */ - tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], false= , true); - tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.idle[prio], - false, false); + if (ctx.protm_group) { + /* Pick only idle groups with equal or lower priority than the + * group triggering protected mode. Do not bother picking + * unscheduled idle groups. + */ + for (prio =3D ctx.protm_group->priority; + prio >=3D 0 && !tick_ctx_is_full(sched, &ctx); + prio--) + tick_ctx_pick_groups_from_list(sched, &ctx, + &ctx.old_groups[prio], + false, true); + } else { + /* No switch to protected, just pick any idle group according + * to priority + */ + for (prio =3D PANTHOR_CSG_PRIORITY_COUNT - 1; + prio >=3D 0 && !tick_ctx_is_full(sched, &ctx); + prio--) { + /* Check the old_group queue first to avoid + * reprogramming the slots + */ + tick_ctx_pick_groups_from_list(sched, &ctx, + &ctx.old_groups[prio], + false, true); + tick_ctx_pick_groups_from_list(sched, &ctx, + &sched->groups.idle[prio], + false, false); + } } =20 tick_ctx_apply(sched, &ctx); @@ -2979,6 +3279,8 @@ void panthor_sched_pre_reset(struct panthor_device *p= tdev) cancel_work_sync(&sched->sync_upd_work); cancel_delayed_work_sync(&sched->tick_work); =20 + handle_protm_fault(ptdev); + panthor_sched_suspend(ptdev); =20 /* Stop all groups that might still accept jobs, so we don't get passed @@ -3004,6 +3306,9 @@ void panthor_sched_post_reset(struct panthor_device *= ptdev, bool reset_failed) =20 mutex_lock(&sched->reset.lock); =20 + group_put(sched->protm.active_group); + sched->protm.active_group =3D NULL; + list_for_each_entry_safe(group, group_tmp, &sched->reset.stopped_groups, = run_node) { /* Consider all previously running group as terminated if the * reset failed. diff --git a/drivers/gpu/drm/panthor/panthor_sched.h b/drivers/gpu/drm/pant= hor/panthor_sched.h index be7e1c8b4f563..fa4a914c9d05a 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.h +++ b/drivers/gpu/drm/panthor/panthor_sched.h @@ -52,4 +52,8 @@ void panthor_sched_report_fw_events(struct panthor_device= *ptdev, u32 events); =20 void panthor_fdinfo_gather_group_samples(struct drm_file *file); =20 +void panthor_sched_protm_block(struct panthor_device *ptdev); +void panthor_sched_protm_unblock(struct panthor_device *ptdev); +int panthor_sched_protm_exit(struct panthor_device *ptdev); + #endif --=20 2.43.0 From nobody Sat Jul 25 22:32:28 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3500B3AA4F7 for ; Sun, 12 Jul 2026 13:55:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864512; cv=none; b=srWBwnT6egmTN/1SpYcx1plMUHup6J4oqWguxR0xG47Yls1ZhNFZl8qdum7FS3IeBfZCqybmqWDqIW8jqcAnQmfVrq3QOBE3YIr8Q9/RJ/ZM6i4ANj23eeNiw4Q+ZOhmUdzDi/Ik4v3EOP1YJlBLzyuIyF8PsuqvMJ1cjPoMNoI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783864512; c=relaxed/simple; bh=onJYnedAjlLDvUCLwn9x8JhUY2iEJvwCicdCVmXtxjE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P09IKKVgPjcv4ulYKTyyljoLu1Awf+alCD39/I3srLZTvkL0eZJyaAzCOVIofp9p1zdgVUQyTYv+A4PM/oAuyelUxrHdyaADGMciSa/7fyKuPrUYb3LOj2MEOhFQ8JshNS8egaSp+LcZdf+PhuapRTOgZtupTi6YN8g+2DNHh1c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=eVReSQ+g; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="eVReSQ+g" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 500761BB2; Sun, 12 Jul 2026 06:55:05 -0700 (PDT) Received: from e120398-lin.trondheim.arm.com (e120398-lin.trondheim.arm.com [10.42.46.160]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DCCD63F7D8; Sun, 12 Jul 2026 06:55:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1783864509; bh=onJYnedAjlLDvUCLwn9x8JhUY2iEJvwCicdCVmXtxjE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eVReSQ+gSAFFdTP2Mw+Uf668mhK3WYMPI4NMWqBCDpLbFLhH/I86Ql80rHOltBvr1 QW9nB/9jvBloRYiJwo52fTWkWOG47G7rAcmhfpsc5A5YkwZ22R9KGEUVLBrX8rRj2x ug8ajOSn0SAlGb7dMLNCd0CVZzLuwM5SYdO0EjsI= From: Ketil Johnsen To: Boris Brezillon , Steven Price , Liviu Dudau , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Daniel Almeida , Alice Ryhl Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Ketil Johnsen Subject: [PATCH v2 7/7] drm/panthor: Expose protected rendering features Date: Sun, 12 Jul 2026 15:54:39 +0200 Message-ID: <20260712135439.1546950-8-ketil.johnsen@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260712135439.1546950-1-ketil.johnsen@arm.com> References: <20260712135439.1546950-1-ketil.johnsen@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Boris Brezillon Extensions to Panthor uAPI: - New IOCTL for user space to provide protected FW memory. - New query for checking protected rendering availability/status and requirements. - Extends group creation to allow user space to provide a protected suspend buffer. The Mali GPU FW needs some protected memory when executing in protected mode. This FW memory section is assigned a VA during device init. A user space process with the needed privileges (CAP_SYS_MODULE) must provide a suitable memory buffer before the Mali GPU is capable of executing in protected mode. Processes who want to execute in protected mode must also ensure they pass a protected suspend buffer during group creation. Added panthor_kernel_bo_import() to allow user provided buffers. Refactor panthor_kernel_bo_create() to allow shared code with the new import variant. Signed-off-by: Boris Brezillon Co-developed-by: Ketil Johnsen Signed-off-by: Ketil Johnsen --- drivers/gpu/drm/panthor/panthor_device.h | 3 + drivers/gpu/drm/panthor/panthor_drv.c | 23 +++- drivers/gpu/drm/panthor/panthor_fw.c | 154 ++++++++++++++++++----- drivers/gpu/drm/panthor/panthor_fw.h | 2 + drivers/gpu/drm/panthor/panthor_gem.c | 102 +++++++++------ drivers/gpu/drm/panthor/panthor_gem.h | 7 +- drivers/gpu/drm/panthor/panthor_sched.c | 45 ++++++- include/uapi/drm/panthor_drm.h | 85 ++++++++++++- 8 files changed, 347 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/pan= thor/panthor_device.h index e5df42f095717..c3fab0a1b77b2 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -351,6 +351,9 @@ struct panthor_device { * in panthor_vm_lock_region() will ensure this is enough. */ struct rw_semaphore lock; + + /** @info: Protected mode info. */ + struct drm_panthor_protm_info info; } protm; }; =20 diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/pantho= r/panthor_drv.c index e18ee2d7a8e6f..6be9f33483e7b 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -178,11 +178,13 @@ panthor_get_uobj_array(const struct drm_panthor_obj_a= rray *in, u32 min_stride, PANTHOR_UOBJ_DECL(struct drm_panthor_mmu_info, page_size_bitmap), \ PANTHOR_UOBJ_DECL(struct drm_panthor_timestamp_info, current_timestamp)= , \ PANTHOR_UOBJ_DECL(struct drm_panthor_group_priorities_info, pad), \ + PANTHOR_UOBJ_DECL(struct drm_panthor_protm_info, pad), \ PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs), \ - PANTHOR_UOBJ_DECL(struct drm_panthor_bo_sync_op, size)) + PANTHOR_UOBJ_DECL(struct drm_panthor_bo_sync_op, size), \ + PANTHOR_UOBJ_DECL(struct drm_panthor_protm_init, pad)) =20 /** * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object. @@ -959,6 +961,10 @@ static int panthor_ioctl_dev_query(struct drm_device *= ddev, void *data, struct d args->size =3D sizeof(ptdev->mmu_info); return 0; =20 + case DRM_PANTHOR_DEV_QUERY_PROTM_INFO: + args->size =3D sizeof(ptdev->protm.info); + return 0; + default: return -EINVAL; } @@ -992,6 +998,9 @@ static int panthor_ioctl_dev_query(struct drm_device *d= dev, void *data, struct d case DRM_PANTHOR_DEV_QUERY_MMU_INFO: return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->mmu_info); =20 + case DRM_PANTHOR_DEV_QUERY_PROTM_INFO: + return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->protm.info); + default: return -EINVAL; } @@ -1589,6 +1598,12 @@ static int panthor_ioctl_bo_query_info(struct drm_de= vice *ddev, void *data, return 0; } =20 +static int panthor_ioctl_protm_init(struct drm_device *ddev, void *data, + struct drm_file *file) +{ + return panthor_fw_protm_init(file, data); +} + static int panthor_open(struct drm_device *ddev, struct drm_file *file) { @@ -1665,6 +1680,7 @@ static const struct drm_ioctl_desc panthor_drm_driver= _ioctls[] =3D { PANTHOR_IOCTL(SET_USER_MMIO_OFFSET, set_user_mmio_offset, DRM_RENDER_ALLO= W), PANTHOR_IOCTL(BO_SYNC, bo_sync, DRM_RENDER_ALLOW), PANTHOR_IOCTL(BO_QUERY_INFO, bo_query_info, DRM_RENDER_ALLOW), + PANTHOR_IOCTL(PROTM_INIT, protm_init, DRM_RENDER_ALLOW), }; =20 static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) @@ -1785,6 +1801,9 @@ static void panthor_debugfs_init(struct drm_minor *mi= nor) * - 1.8 - extends DEV_QUERY_TIMESTAMP_INFO with flags * - 1.9 - adds DRM_PANTHOR_DEV_QUERY_MMU_INFO query * - adds DRM_PANTHOR_VM_BIND_OP_MAP_SPARSE flag + * - 1.10 - adds DRM_IOCTL_PANTHOR_PROTM_INIT ioctl + * - adds DRM_PANTHOR_DEV_QUERY_PROTM_INFO query + * - adds drm_panthor_group_create::protected_suspend_bo_handle */ static const struct drm_driver panthor_drm_driver =3D { .driver_features =3D DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | @@ -1798,7 +1817,7 @@ static const struct drm_driver panthor_drm_driver =3D= { .name =3D "panthor", .desc =3D "Panthor DRM driver", .major =3D 1, - .minor =3D 9, + .minor =3D 10, =20 .gem_prime_import_sg_table =3D panthor_gem_prime_import_sg_table, .gem_prime_import =3D panthor_gem_prime_import, diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor= /panthor_fw.c index 76792f9175b57..d282aef84ce4f 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -13,8 +13,10 @@ #include #include #include +#include =20 #include +#include #include #include =20 @@ -198,6 +200,12 @@ struct panthor_fw_section { /** @size: Size of @buf in bytes. */ size_t size; } data; + + /** @size: Section size. */ + size_t size; + + /** @va: Section VA. */ + u32 va; }; =20 #define CSF_MCU_SHARED_REGION_START 0x04000000ULL @@ -246,6 +254,9 @@ struct panthor_fw { /** @shared_section: The section containing the FW interfaces. */ struct panthor_fw_section *shared_section; =20 + /** @protm_section: The protected mode section. */ + struct panthor_fw_section *protm_section; + /** @iface: FW interfaces. */ struct panthor_fw_iface iface; =20 @@ -255,6 +266,9 @@ struct panthor_fw { struct delayed_work ping_work; } watchdog; =20 + /** @protm_init_lock: Used to serialize protm initialization. */ + struct mutex protm_init_lock; + /** * @req_waitqueue: FW request waitqueue. * @@ -542,6 +556,30 @@ panthor_fw_alloc_suspend_buf_mem(struct panthor_device= *ptdev, size_t size) "FW suspend buffer"); } =20 +static u32 section_vm_map_flags(const struct panthor_fw_section *section) +{ + u32 cache_mode =3D section->flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_= MASK; + u32 vm_map_flags =3D 0; + + if (!(section->flags & CSF_FW_BINARY_IFACE_ENTRY_WR)) + vm_map_flags |=3D DRM_PANTHOR_VM_BIND_OP_MAP_READONLY; + + if (!(section->flags & CSF_FW_BINARY_IFACE_ENTRY_EX)) + vm_map_flags |=3D DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC; + + /* TODO: CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_*_COHERENT are mapped to + * non-cacheable for now. We might want to introduce a new + * IOMMU_xxx flag (or abuse IOMMU_MMIO, which maps to device + * memory and is currently not used by our driver) for + * AS_MEMATTR_AARCH64_SHARED memory, so we can take benefit + * of IO-coherent systems. + */ + if (cache_mode !=3D CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_CACHED) + vm_map_flags |=3D DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED; + + return vm_map_flags; +} + static int panthor_fw_load_section_entry(struct panthor_device *ptdev, const struct firmware *fw, struct panthor_fw_binary_iter *iter, @@ -550,7 +588,6 @@ static int panthor_fw_load_section_entry(struct panthor= _device *ptdev, ssize_t vm_pgsz =3D panthor_vm_page_size(ptdev->fw->vm); struct panthor_fw_binary_section_entry_hdr hdr; struct panthor_fw_section *section; - u32 section_size; u32 name_len; int ret; =20 @@ -588,12 +625,6 @@ static int panthor_fw_load_section_entry(struct pantho= r_device *ptdev, return -EINVAL; } =20 - if (hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT) { - drm_warn(&ptdev->base, - "Firmware protected mode entry is not supported, ignoring"); - return 0; - } - if (hdr.va.start =3D=3D CSF_MCU_SHARED_REGION_START && !(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_SHARED)) { drm_err(&ptdev->base, @@ -632,36 +663,34 @@ static int panthor_fw_load_section_entry(struct panth= or_device *ptdev, section->name =3D name; } =20 - section_size =3D hdr.va.end - hdr.va.start; - if (section_size) { - u32 cache_mode =3D hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_MASK; - u32 vm_map_flags =3D 0; - u64 va =3D hdr.va.start; + section->size =3D hdr.va.end - hdr.va.start; + section->va =3D hdr.va.start; =20 - if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_WR)) - vm_map_flags |=3D DRM_PANTHOR_VM_BIND_OP_MAP_READONLY; + if (hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT) { + if (ptdev->fw->protm_section) { + drm_err(&ptdev->base, "Only one protected section supported\n"); + return -EINVAL; + } =20 - if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_EX)) - vm_map_flags |=3D DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC; + ptdev->protm.info.fw_protected_sections_size =3D ALIGN(section->size, vm= _pgsz); + ptdev->fw->protm_section =3D section; + } =20 - /* TODO: CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_*_COHERENT are mapped to - * non-cacheable for now. We might want to introduce a new - * IOMMU_xxx flag (or abuse IOMMU_MMIO, which maps to device - * memory and is currently not used by our driver) for - * AS_MEMATTR_AARCH64_SHARED memory, so we can take benefit - * of IO-coherent systems. - */ - if (cache_mode !=3D CSF_FW_BINARY_IFACE_ENTRY_CACHE_MODE_CACHED) - vm_map_flags |=3D DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED; + /* Defer the section->mem creation if this is a protected entry. + * This will be populated when DRM_IOCTL_PANTHOR_PROTM_INIT is called. + */ + if (section->size && !(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_PROT)) { + u32 vm_map_flags =3D section_vm_map_flags(section); =20 section->mem =3D panthor_kernel_bo_create(ptdev, panthor_fw_vm(ptdev), - section_size, + section->size, DRM_PANTHOR_BO_NO_MMAP, - vm_map_flags, va, "FW section"); + vm_map_flags, section->va, + "FW section"); if (IS_ERR(section->mem)) return PTR_ERR(section->mem); =20 - if (drm_WARN_ON(&ptdev->base, section->mem->va_node.start !=3D hdr.va.st= art)) + if (drm_WARN_ON(&ptdev->base, section->mem->va_node.start !=3D section->= va)) return -EINVAL; =20 if (section->flags & CSF_FW_BINARY_IFACE_ENTRY_SHARED) { @@ -942,6 +971,11 @@ static int panthor_init_csg_iface(struct panthor_devic= e *ptdev, return -EINVAL; } =20 + if (!csg_idx) { + ptdev->protm.info.group_protected_suspend_buf_size =3D + csg_iface->control->protm_suspend_size; + } + if (csg_idx > 0) { struct panthor_fw_csg_iface *first_csg_iface =3D panthor_fw_get_csg_iface(ptdev, 0); @@ -1529,6 +1563,66 @@ int panthor_fw_protm_exit(struct panthor_device *ptd= ev) return panthor_fw_protm_exit_wait(ptdev, 500); } =20 +int panthor_fw_protm_init(struct drm_file *file, + struct drm_panthor_protm_init *args) +{ + struct panthor_file *pfile =3D file->driver_priv; + struct panthor_device *ptdev =3D pfile->ptdev; + struct panthor_fw_section *protm_section =3D ptdev->fw->protm_section; + struct drm_gem_object *obj; + u32 vm_map_flags; + int cookie, ret =3D 0; + + if (!capable(CAP_SYS_MODULE)) + return -EPERM; + + if (args->pad) + return -EINVAL; + + if (!protm_section || !protm_section->size) + return -EINVAL; + + guard(mutex)(&ptdev->fw->protm_init_lock); + + if (ptdev->protm.info.state & DRM_PANTHOR_PROTM_INITIALIZED) + return 0; + + if (!drm_dev_enter(&ptdev->base, &cookie)) + return -ENODEV; + + obj =3D drm_gem_object_lookup(file, args->fw_protected_sections_bo_handle= ); + if (!obj) { + ret =3D -ENOENT; + goto out_dev_exit; + } + + if (obj->size < ptdev->protm.info.fw_protected_sections_size) { + ret =3D -EINVAL; + goto out_gem_put; + } + + vm_map_flags =3D section_vm_map_flags(protm_section); + + protm_section->mem =3D panthor_kernel_bo_import(ptdev, panthor_fw_vm(ptde= v), + to_panthor_bo(obj), + vm_map_flags, protm_section->va, + protm_section->size); + if (IS_ERR(protm_section->mem)) { + ret =3D PTR_ERR(protm_section->mem); + protm_section->mem =3D NULL; + goto out_gem_put; + } + + ptdev->protm.info.state |=3D DRM_PANTHOR_PROTM_INITIALIZED; + +out_gem_put: + drm_gem_object_put(obj); + +out_dev_exit: + drm_dev_exit(cookie); + return ret; +} + /** * panthor_fw_init() - Initialize FW related data. * @ptdev: Device. @@ -1550,6 +1644,10 @@ int panthor_fw_init(struct panthor_device *ptdev) INIT_LIST_HEAD(&fw->sections); INIT_DELAYED_WORK(&fw->watchdog.ping_work, panthor_fw_ping_work); =20 + ret =3D drmm_mutex_init(&ptdev->base, &fw->protm_init_lock); + if (ret) + return ret; + irq =3D platform_get_irq_byname(to_platform_device(ptdev->base.dev), "job= "); if (irq <=3D 0) return -ENODEV; diff --git a/drivers/gpu/drm/panthor/panthor_fw.h b/drivers/gpu/drm/panthor= /panthor_fw.h index 78658d64b807e..dbd3e58f04eb6 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.h +++ b/drivers/gpu/drm/panthor/panthor_fw.h @@ -529,6 +529,8 @@ static inline int panthor_fw_resume(struct panthor_devi= ce *ptdev) int panthor_fw_init(struct panthor_device *ptdev); void panthor_fw_unplug(struct panthor_device *ptdev); =20 +int panthor_fw_protm_init(struct drm_file *file, + struct drm_panthor_protm_init *args); int panthor_fw_protm_enter(struct panthor_device *ptdev); int panthor_fw_protm_exit(struct panthor_device *ptdev); int panthor_fw_protm_exit_wait(struct panthor_device *ptdev, diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/pantho= r/panthor_gem.c index 9855df7381947..69ef4b6012b4f 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -74,14 +74,14 @@ static void panthor_gem_debugfs_bo_rm(struct panthor_ge= m_object *bo) mutex_unlock(&ptdev->gems.lock); } =20 -static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object = *bo, u32 usage_flags) +static void panthor_gem_debugfs_add_usage_flags(struct panthor_gem_object = *bo, u32 usage_flags) { - bo->debugfs.flags =3D usage_flags; - panthor_gem_debugfs_bo_add(bo); + atomic_or(usage_flags, &bo->debugfs.flags); } #else +static void panthor_gem_debugfs_bo_add(struct panthor_gem_object *bo) {} static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {} -static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object = *bo, u32 usage_flags) {} +static void panthor_gem_debugfs_add_usage_flags(struct panthor_gem_object = *bo, u32 usage_flags) {} static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {} #endif =20 @@ -1027,7 +1027,7 @@ panthor_gem_create(struct drm_device *dev, size_t siz= e, uint32_t flags, bo->base.resv =3D bo->exclusive_vm_root_gem->resv; } =20 - panthor_gem_debugfs_set_usage_flags(bo, usage_flags); + panthor_gem_debugfs_bo_add(bo); return bo; =20 err_put: @@ -1253,7 +1253,9 @@ void panthor_kernel_bo_destroy(struct panthor_kernel_= bo *bo) panthor_kernel_bo_vunmap(bo); =20 drm_WARN_ON(bo->obj->dev, - to_panthor_bo(bo->obj)->exclusive_vm_root_gem !=3D panthor_vm_root_g= em(vm)); + to_panthor_bo(bo->obj)->exclusive_vm_root_gem && + (to_panthor_bo(bo->obj)->exclusive_vm_root_gem !=3D + panthor_vm_root_gem(vm))); panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size); panthor_vm_free_va(vm, &bo->va_node); if (vm =3D=3D panthor_fw_vm(ptdev)) @@ -1264,46 +1266,32 @@ void panthor_kernel_bo_destroy(struct panthor_kerne= l_bo *bo) } =20 /** - * panthor_kernel_bo_create() - Create and map a GEM object to a VM + * panthor_kernel_bo_import() - Create a kernel BO from an existing GEM ob= ject * @ptdev: Device. * @vm: VM to map the GEM to. - * @size: Size of the buffer object. - * @bo_flags: Combination of drm_panthor_bo_flags flags. + * @bo: BO to use for our kernel BO. * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those * that are related to map operations). * @gpu_va: GPU address assigned when mapping to the VM. * If gpu_va =3D=3D PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be * automatically allocated. - * @name: Descriptive label of the BO's contents + * @vm_map_size: Size of the BO to map to the VM. * * Return: A valid pointer in case of success, an ERR_PTR() otherwise. */ struct panthor_kernel_bo * -panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *= vm, - size_t size, u32 bo_flags, u32 vm_map_flags, - u64 gpu_va, const char *name) +panthor_kernel_bo_import(struct panthor_device *ptdev, struct panthor_vm *= vm, + struct panthor_gem_object *bo, + u32 vm_map_flags, u64 gpu_va, u32 vm_map_size) { struct panthor_kernel_bo *kbo; - struct panthor_gem_object *bo; - u32 debug_flags =3D PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL; int ret; =20 - if (drm_WARN_ON(&ptdev->base, !vm)) - return ERR_PTR(-EINVAL); - kbo =3D kzalloc_obj(*kbo); if (!kbo) return ERR_PTR(-ENOMEM); =20 - if (vm =3D=3D panthor_fw_vm(ptdev)) - debug_flags |=3D PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; - - bo =3D panthor_gem_create(&ptdev->base, size, bo_flags, vm, debug_flags); - if (IS_ERR(bo)) { - ret =3D PTR_ERR(bo); - goto err_free_kbo; - } - + drm_gem_object_get(&bo->base); kbo->obj =3D &bo->base; =20 if (vm =3D=3D panthor_fw_vm(ptdev)) { @@ -1312,24 +1300,26 @@ panthor_kernel_bo_create(struct panthor_device *ptd= ev, struct panthor_vm *vm, goto err_put_obj; } =20 - panthor_gem_kernel_bo_set_label(kbo, name); - /* The system and GPU MMU page size might differ, which becomes a * problem for FW sections that need to be mapped at explicit address * since our PAGE_SIZE alignment might cover a VA range that's * expected to be used for another section. * Make sure we never map more than we need. */ - size =3D ALIGN(size, panthor_vm_page_size(vm)); - ret =3D panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node); + vm_map_size =3D ALIGN(vm_map_size, panthor_vm_page_size(vm)); + ret =3D panthor_vm_alloc_va(vm, gpu_va, vm_map_size, &kbo->va_node); if (ret) goto err_unpin; =20 - ret =3D panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_m= ap_flags); + ret =3D panthor_vm_map_bo_range(vm, bo, 0, vm_map_size, + kbo->va_node.start, vm_map_flags); if (ret) goto err_free_va; =20 kbo->vm =3D panthor_vm_get(vm); + if (vm =3D=3D panthor_fw_vm(ptdev)) + panthor_gem_debugfs_add_usage_flags(bo, PANTHOR_DEBUGFS_GEM_USAGE_FLAG_F= W_MAPPED); + return kbo; =20 err_free_va: @@ -1341,12 +1331,54 @@ panthor_kernel_bo_create(struct panthor_device *ptd= ev, struct panthor_vm *vm, =20 err_put_obj: drm_gem_object_put(&bo->base); - -err_free_kbo: kfree(kbo); return ERR_PTR(ret); } =20 +/** + * panthor_kernel_bo_create() - Create and map a GEM object to a VM + * @ptdev: Device. + * @vm: VM to map the GEM to. + * @size: Size of the buffer object. + * @bo_flags: Combination of drm_panthor_bo_flags flags. + * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those + * that are related to map operations). + * @gpu_va: GPU address assigned when mapping to the VM. + * If gpu_va =3D=3D PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be + * automatically allocated. + * @name: Descriptive label of the BO's contents + * + * Return: A valid pointer in case of success, an ERR_PTR() otherwise. + */ +struct panthor_kernel_bo * +panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *= vm, + size_t size, u32 bo_flags, u32 vm_map_flags, + u64 gpu_va, const char *name) +{ + struct panthor_kernel_bo *kbo; + struct panthor_gem_object *bo; + + if (drm_WARN_ON(&ptdev->base, !vm)) + return ERR_PTR(-EINVAL); + + bo =3D panthor_gem_create(&ptdev->base, size, bo_flags, vm, 0); + if (IS_ERR(bo)) + return ERR_CAST(bo); + + kbo =3D panthor_kernel_bo_import(ptdev, vm, bo, vm_map_flags, gpu_va, + size); + if (!IS_ERR(kbo)) { + panthor_gem_debugfs_add_usage_flags(bo, PANTHOR_DEBUGFS_GEM_USAGE_FLAG_K= ERNEL); + panthor_gem_kernel_bo_set_label(kbo, name); + } + + /* panthor_kernel_bo_import() acquires a GEM ref if the import succeeds, = so + * we can release it unconditionally here. + */ + drm_gem_object_put(&bo->base); + return kbo; +} + /** * panthor_dummy_bo_create() - Create a Panthor BO meant to back sparse bi= ndings. * @ptdev: Device. @@ -1642,9 +1674,9 @@ static void panthor_gem_debugfs_bo_print(struct panth= or_gem_object *bo, enum panthor_gem_reclaim_state reclaim_state =3D bo->reclaim_state; unsigned int refcount =3D kref_read(&bo->base.refcount); int reclaimed_count =3D atomic_read(&bo->reclaimed_count); + u32 gem_usage_flags =3D atomic_read(&bo->debugfs.flags); char creator_info[32] =3D {}; size_t resident_size; - u32 gem_usage_flags =3D bo->debugfs.flags; u32 gem_state_flags =3D 0; =20 /* Skip BOs being destroyed. */ diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/pantho= r/panthor_gem.h index 5ae37d0d3646f..7e88f5dcbff54 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -62,7 +62,7 @@ struct panthor_gem_debugfs { } creator; =20 /** @flags: Combination of panthor_debugfs_gem_usage_flags flags */ - u32 flags; + atomic_t flags; }; =20 /** @@ -318,6 +318,11 @@ panthor_kernel_bo_vunmap(struct panthor_kernel_bo *bo) } } =20 +struct panthor_kernel_bo * +panthor_kernel_bo_import(struct panthor_device *ptdev, struct panthor_vm *= vm, + struct panthor_gem_object *bo, + u32 vm_map_flags, u64 gpu_va, u32 vm_map_size); + struct panthor_kernel_bo * panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *= vm, size_t size, u32 bo_flags, u32 vm_map_flags, diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/pant= hor/panthor_sched.c index efa53b0a05d38..15c7bb34a865d 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -1508,10 +1508,15 @@ cs_slot_process_protm_pending_event_locked(struct p= anthor_device *ptdev, if (!group) return; =20 - /* Do not allow user space work to switch into protected mode, as we - * do not fully support this quite yet. + /* Do not allow user space work to switch into protected mode if we + * do not support protected mode on this device. + * User space should query (and init) this support before attempting + * to use such GPU instructions. */ - group->fatal_queues |=3D BIT(cs_id); + if (!(ptdev->protm.info.state & DRM_PANTHOR_PROTM_INITIALIZED)) + group->fatal_queues |=3D BIT(cs_id); + else + group->protm_pending_queues |=3D BIT(cs_id); =20 sched_queue_delayed_work(sched, tick, 0); } @@ -3962,6 +3967,7 @@ static void add_group_kbo_sizes(struct panthor_device= *ptdev, } =20 #define MAX_GROUPS_PER_POOL 128 +#define GROUP_CREATE_FLAGS DRM_PANTHOR_GROUP_CREATE_PROTECTED =20 int panthor_group_create(struct drm_file *file, const struct drm_panthor_group_create *group_args, @@ -3976,9 +3982,6 @@ int panthor_group_create(struct drm_file *file, u32 gid, i, suspend_size; int ret; =20 - if (group_args->pad) - return -EINVAL; - if (group_args->priority >=3D PANTHOR_CSG_PRIORITY_COUNT) return -EINVAL; =20 @@ -4031,6 +4034,36 @@ int panthor_group_create(struct drm_file *file, goto err_put_group; } =20 + if (group_args->protected_suspend_bo_handle) { + struct drm_gem_object *obj; + + obj =3D drm_gem_object_lookup(file, group_args->protected_suspend_bo_han= dle); + if (!obj) { + ret =3D -ENOENT; + goto err_put_group; + } + + if (obj->size < ptdev->protm.info.group_protected_suspend_buf_size) { + drm_gem_object_put(obj); + ret =3D -EINVAL; + goto err_put_group; + } + + suspend_size =3D csg_iface->control->protm_suspend_size; + group->protm_suspend_buf =3D + panthor_kernel_bo_import(ptdev, panthor_fw_vm(ptdev), + to_panthor_bo(obj), + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, + PANTHOR_VM_KERNEL_AUTO_VA, + suspend_size); + drm_gem_object_put(obj); + if (IS_ERR(group->protm_suspend_buf)) { + ret =3D PTR_ERR(group->protm_suspend_buf); + group->protm_suspend_buf =3D NULL; + goto err_put_group; + } + } + group->syncobjs =3D panthor_kernel_bo_create(ptdev, group->vm, group_args->queues.count * sizeof(struct panthor_syncobj_64b), diff --git a/include/uapi/drm/panthor_drm.h b/include/uapi/drm/panthor_drm.h index a2ff0f4ec6915..a0ed16041e178 100644 --- a/include/uapi/drm/panthor_drm.h +++ b/include/uapi/drm/panthor_drm.h @@ -154,6 +154,11 @@ enum drm_panthor_ioctl_id { * This is useful for imported BOs. */ DRM_PANTHOR_BO_QUERY_INFO, + + /** + * @DRM_PANTHOR_PROTM_INIT: Device-wide initialize of protected mode. + */ + DRM_PANTHOR_PROTM_INIT, }; =20 /** @@ -256,6 +261,11 @@ enum drm_panthor_dev_query_type { =20 /** @DRM_PANTHOR_DEV_QUERY_MMU_INFO: Query MMU information. */ DRM_PANTHOR_DEV_QUERY_MMU_INFO, + + /** + * @DRM_PANTHOR_DEV_QUERY_PROTM_INFO: Query supported protected rendering= information. + */ + DRM_PANTHOR_DEV_QUERY_PROTM_INFO, }; =20 /** @@ -517,6 +527,51 @@ struct drm_panthor_group_priorities_info { __u8 pad[3]; }; =20 +/** + * enum drm_panthor_protm_state_flags - Describes the state of the protect= ed mode feature. + * + * List of GPU states which can be used by the GPU to access protected mem= ory. + */ +enum drm_panthor_protm_state_flags { + /** + * @DRM_PANTHOR_PROTM_INITIALIZED: Device-wide initialization of the + * protected mode feature is done. + */ + DRM_PANTHOR_PROTM_INITIALIZED =3D 1 << 0, +}; + +/** + * struct drm_panthor_protm_info - Protected mode info. + * + * Structure grouping all queryable information relating to protected mode. + */ +struct drm_panthor_protm_info { + /** + * @state: Combination of enum drm_panthor_protm_state_flags flags. + */ + __u32 state; + + /** + * @fw_protected_sections_size: Size of all the protected FW sections. + * + * Size of the protected buffer to pass through + * DRM_IOCTL_PANTHOR_PROTM_INIT. + */ + __u32 fw_protected_sections_size; + + /** + * @group_protected_suspend_buf_size: Size of the group suspend buffer. + * + * This must be used to allocate a protected BO that's big enough to use + * as a protected suspend buffer when a group supports protected + * rendering. + */ + __u32 group_protected_suspend_buf_size; + + /** @pad: MBZ. */ + __u32 pad; +}; + /** * struct drm_panthor_dev_query - Arguments passed to DRM_PANTHOR_IOCTL_DE= V_QUERY */ @@ -901,8 +956,14 @@ struct drm_panthor_group_create { /** @priority: Group priority (see enum drm_panthor_group_priority). */ __u8 priority; =20 - /** @pad: Padding field, MBZ. */ - __u32 pad; + /** + * @protected_suspend_bo_handle: BO to use as a protected suspend buffer. + * + * This BO must have been allocated from a protected DMA-BUF heap and + * imported in panthor. It's size must be at least + * drm_panthor_protm_info::group_protected_suspend_buf_size. + */ + __u32 protected_suspend_bo_handle; =20 /** * @compute_core_mask: Mask encoding cores that can be used for compute j= obs. @@ -1270,6 +1331,24 @@ struct drm_panthor_bo_query_info { __u32 pad; }; =20 +/** + * struct drm_panthor_protm_init - Protected mode initialization arguments. + */ +struct drm_panthor_protm_init { + /** + * @fw_protected_sections_bo_handle: Handle of the BO to use for the FW p= rotected + * sections. + * + * This BO must have been allocated from a protected DMA-BUF heap and + * imported in panthor. It's size must be at least + * drm_panthor_protm_info::fw_protected_sections_size. + */ + __u32 fw_protected_sections_bo_handle; + + /** @pad: MBZ. */ + __u32 pad; +}; + /** * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number * @__access: Access type. Must be R, W or RW. @@ -1320,6 +1399,8 @@ enum { DRM_IOCTL_PANTHOR(WR, BO_SYNC, bo_sync), DRM_IOCTL_PANTHOR_BO_QUERY_INFO =3D DRM_IOCTL_PANTHOR(WR, BO_QUERY_INFO, bo_query_info), + DRM_IOCTL_PANTHOR_PROTM_INIT =3D + DRM_IOCTL_PANTHOR(WR, PROTM_INIT, protm_init), }; =20 #if defined(__cplusplus) --=20 2.43.0