Re: [PATCH] drm/msm/adreno: Only check for PAS when a zap shader is present

From: Sumit Garg

Date: Thu Sep 10 2026 - 03:35:01 EST


On Fri, Aug 21, 2026 at 1:44 PM Paul Hollinsky
<phollinsky@xxxxxxxxxxxxxx> wrote:
>
> Commit 0be72be03ca7 ("drm/msm: Switch to generic PAS TZ APIs") replaced
> the qcom_scm_is_available() check in adreno_zap_shader_load() with
> qcom_pas_is_available(). These are not equivalent: the former reports
> whether the SCM transport is up, the latter whether the TrustZone
> firmware implements the peripheral authentication service.
>
> On SC7180 Chromebooks (trogdor) TZ does not implement PAS at all. SCM
> call-availability queries return 0 for every PAS command while other
> services answer normally:
>
> svc 0x06 cmd 0x01 IS_CALL_AVAIL -> 1
> svc 0x02 cmd 0x01 PAS_INIT_IMAGE -> 0
> svc 0x02 cmd 0x05 PAS_AUTH_RESET -> 0
> svc 0x02 cmd 0x07 PAS_IS_SUPPORTED -> 0
> svc 0x0c cmd 0x16 MP_ASSIGN -> 1
> svc 0x05 cmd 0x01 IO_READ -> 1
>
> so qcom_scm_probe() never registers a PAS backend and
> qcom_pas_is_available() is false for the lifetime of the boot.
>
> That on its own need not matter, because sc7180-trogdor.dtsi does
> /delete-node/ &gpu_zap_shader;, and the intended path for such a board
> is for zap_shader_load_mdt() to find no zap-shader child, clear
> zap_available, return -ENODEV, and let the caller fall back to
> SECVID_TRUST_CNTL.
>
> The problem is the ordering. zap_available is a static initialised to
> true and is only ever cleared inside zap_shader_load_mdt(), but
> adreno_zap_shader_load() consults PAS before calling it. The discovery
> that decides whether a zap shader is needed at all can therefore never
> run, the flag is never cleared, and every call returns -EPROBE_DEFER:
>
> adreno 5000000.gpu: [drm:adreno_zap_shader_load] *ERROR* PAS is not available
> msm_dpu ae01000.display-controller: [drm:adreno_load_gpu] *ERROR* gpu hw init failed: -517
>
> Nothing retries that deferral, either. adreno_zap_shader_load() is
> called from a6xx_hw_init() rather than from probe, so the -EPROBE_DEFER
> is not a probe return value: it propagates up until adreno_load_gpu()
> returns NULL. load_gpu() re-attempts on every DRM open while priv->gpu
> is NULL, each open fails identically, and PAS cannot become available in
> between - which is why the error repeats and userspace stays on
> llvmpipe.
>
> Move the availability check into zap_shader_load_mdt(), behind the
> zap-shader node lookup, so the driver only consults PAS once it knows it
> needs PAS. Boards with no zap-shader node take the intended -ENODEV
> fallback without ever asking, and boards that do have one keep the
> qcom_pas_is_available() gate.
>
> Fixes: 0be72be03ca7 ("drm/msm: Switch to generic PAS TZ APIs")
> Link: https://lore.kernel.org/r/20260808034716.58888-1-phollinsky@xxxxxxxxxxxxxx
> Signed-off-by: Paul Hollinsky <phollinsky@xxxxxxxxxxxxxx>
> ---
> Reported and analysed in:
> https://lore.kernel.org/linux-arm-msm/20260808034716.58888-1-phollinsky@xxxxxxxxxxxxxx/
> Konrad agreed with this shape in
> https://lore.kernel.org/linux-arm-msm/b63e93e4-2f4c-4cad-b726-e1b0565379d7@xxxxxxxxx/
>
> 0be72be03ca7 landed in mainline during the v7.3 merge window (via the
> soc-drivers-7.3 pull), so this is based on Linus' tree. Note that
> msm-fixes and msm-next both still predate it as I write this, so it
> needs a base that includes the merge window; happy to respin against
> whatever base you prefer, and it can equally go via the qcom tree the
> culprit came through.
>
> Tested on a Lenovo IdeaPad Duet 3 (sc7180-trogdor-wormdingler) on
> next-20260805, which carries the same code: with this applied the GPU
> initialises and logs "Zap shader not enabled - using SECVID_TRUST_CNTL
> instead", and userspace gets a6xx rather than llvmpipe.
>
> drivers/gpu/drm/msm/adreno/adreno_gpu.c | 13 ++++++-------
> 1 file changed, 6 insertions(+), 7 deletions(-)
>

Reviewed-by: Sumit Garg <sumit.garg@xxxxxxxxxxxxxxxx>

-Sumit

> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> index 489462065ea9..995161215ad5 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> @@ -52,6 +52,12 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
> return -ENODEV;
> }
>
> + /* We need PAS to be able to load the firmware */
> + if (!qcom_pas_is_available()) {
> + DRM_DEV_ERROR(dev, "PAS is not available\n");
> + return -EPROBE_DEFER;
> + }
> +
> ret = of_reserved_mem_region_to_resource(np, 0, &r);
> if (ret) {
> zap_available = false;
> @@ -170,18 +176,11 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
> int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid)
> {
> struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
> - struct platform_device *pdev = gpu->pdev;
>
> /* Short cut if we determine the zap shader isn't available/needed */
> if (!zap_available)
> return -ENODEV;
>
> - /* We need PAS to be able to load the firmware */
> - if (!qcom_pas_is_available()) {
> - DRM_DEV_ERROR(&pdev->dev, "PAS is not available\n");
> - return -EPROBE_DEFER;
> - }
> -
> return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid);
> }
>
>
> base-commit: 818bebeb63dd6bf5f4e07e145f6cdbace520a34c
> --
> 2.55.0
>