Thank you for your contribution! Sashiko AI review found 2 potential issue(s) 
to consider:
- [High] accel/qda: non-zero remote_session_id in qda_fastrpc_invoke_pack() for 
dsp info
- [Medium] accel/qda: destroyed mutex qdev->attr_lock while held in 
qda_deinit_device()
--

commit 8c89a0764b44acd4840198a5f29101cbf6dc706a
Author: Ekansh Gupta <[email protected]>

accel/qda: Add DSP capability query

This commit adds a QDA_QUERY_DSP_CAPABILITIES query type to
DRM_IOCTL_QDA_QUERY to fetch DSP capability attributes through the DSP
utilities handle and cache them on the device for subsequent queries.

> diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
> index 1e72dce769b9a..51d8ef10c6c1a 100644
> --- a/drivers/accel/qda/qda_drv.c
> +++ b/drivers/accel/qda/qda_drv.c
> @@ -154,6 +154,7 @@ struct qda_dev *qda_alloc_device(struct device *dev)
>  
>       INIT_LIST_HEAD(&qdev->cb_devs);
>       mutex_init(&qdev->import_lock);
> +     mutex_init(&qdev->attr_lock);
>       xa_init_flags(&qdev->ctx_xa, XA_FLAGS_ALLOC1);
>       atomic64_set(&qdev->ctx_seq, 0);
>       atomic_set(&qdev->session_id_seq, 0);
> @@ -181,6 +182,7 @@ void qda_deinit_device(struct qda_dev *qdev)
>       qda_memory_manager_exit(qdev->iommu_mgr);
>       xa_destroy(&qdev->ctx_xa);
>       mutex_destroy(&qdev->import_lock);
> +     mutex_destroy(&qdev->attr_lock);
>  }

[Severity: Medium]
Can mutex_destroy(&qdev->attr_lock) in qda_deinit_device() run while
qdev->attr_lock is still held or waited on by qda_get_dsp_capability()?

In qda_get_dsp_capability(), qdev->attr_lock is held across
qda_fastrpc_invoke():

drivers/accel/qda/qda_ioctl.c:qda_get_dsp_capability() {
        guard(mutex)(&qdev->attr_lock);

        if (!qdev->valid_attributes) {
                err = qda_fastrpc_invoke(QDA_FASTRPC_TYPE_GET_DSP_INFO, 
qdev->dsp_attributes,
                                         session);
}

Inside qda_fastrpc_invoke() -> qda_fastrpc_invoke_common(),
qda_rpmsg_send_msg() calls drm_dev_exit() after rpmsg_send(), and then
qda_rpmsg_wait_for_rsp() sleeps in wait_for_completion_interruptible(&ctx->work)
while qdev->attr_lock remains held.

If the remote processor crashes or the rpmsg device is removed before the
DSP replies, qda_rpmsg_remove() runs:

drivers/accel/qda/qda_rpmsg.c:qda_rpmsg_remove() {
        drm_dev_unplug(&qdev->drm_dev);
        qdev->rpdev = NULL;
        qda_fastrpc_flush_pending(qdev);
        qda_cb_unpopulate(qdev);
        qda_deinit_device(qdev);
}

Because the waiting thread already exited the drm_dev_enter() section,
drm_dev_unplug() does not wait for it. qda_fastrpc_flush_pending() wakes
the invocation with complete(&ctx->work) and qda_rpmsg_remove() proceeds
directly to qda_deinit_device() -> mutex_destroy(&qdev->attr_lock) before
the woken thread in qda_get_dsp_capability() has unlocked qdev->attr_lock.

> diff --git a/drivers/accel/qda/qda_fastrpc.c b/drivers/accel/qda/qda_fastrpc.c
> index e9688e3ba4048..6044cfad53e96 100644
> --- a/drivers/accel/qda/qda_fastrpc.c
> +++ b/drivers/accel/qda/qda_fastrpc.c

[ ... ]

> @@ -980,6 +987,43 @@ static int qda_fastrpc_prepare_args_create_static(struct 
> qda_fastrpc_invoke_ctx
>       return 0;
>  }
>  
> +/*
> + * DSP capability query packed layout:
> + *   [0] count       sizeof(u32), the capacity of the array below    IN
> + *   [1] attrs       (QDA_MAX_DSP_ATTRIBUTES - 1) * sizeof(u32)      OUT
> + *
> + * Index 0 of the cached array is reserved, so only the rest is exchanged.
> + */
> +static int qda_fastrpc_prepare_args_get_dsp_info(struct 
> qda_fastrpc_invoke_ctx *ctx)
> +{
> +     const u32 attr_count = QDA_MAX_DSP_ATTRIBUTES - 1;
> +     struct qda_gem_obj *kernel_gem;
> +     int err;
> +
> +     const size_t off_attrs = sizeof(u32);
> +     const size_t total_size = off_attrs + attr_count * sizeof(u32);
> +
> +     ctx->sc = QDA_FASTRPC_SCALARS(0, 1, 1);
> +     ctx->handle = QDA_FASTRPC_DSP_UTILITIES_HANDLE;

[Severity: High]
When ctx->handle is set to QDA_FASTRPC_DSP_UTILITIES_HANDLE here, should
qda_fastrpc_invoke_pack() also set msg->fastrpc.remote_session_id to 0?

Currently, qda_fastrpc_invoke_pack() only checks for QDA_FASTRPC_INIT_HANDLE:

drivers/accel/qda/qda_fastrpc.c:qda_fastrpc_invoke_pack() {
        /* The session has no process yet to identify while one is being 
created */
        if (ctx->handle == QDA_FASTRPC_INIT_HANDLE)
                msg->fastrpc.remote_session_id = 0;
        else
                msg->fastrpc.remote_session_id = 
ctx->session->remote_session_id;
}

When userspace issues DRM_IOCTL_QDA_QUERY with QDA_QUERY_DSP_CAPABILITIES
before creating a DSP process on the session, qda_fastrpc_invoke_pack()
will pack the session's non-zero remote_session_id into the RPMsg wire
header for a stateless utilities call that has no remote process context
(whereas drivers/misc/fastrpc.c passes kernel = true in
fastrpc_get_info_from_dsp() so fastrpc_invoke_send() sets msg->client_id = 0).

-- 
Sashiko AI review ยท 
https://sashiko.dev/#/patchset/[email protected]?part=23

Reply via email to