]> www.infradead.org Git - users/hch/misc.git/commitdiff
accel/qaic: Synchronize access to DBC request queue head & tail pointer
authorPranjal Ramajor Asha Kanojiya <quic_pkanojiy@quicinc.com>
Tue, 7 Oct 2025 06:18:37 +0000 (08:18 +0200)
committerJeff Hugo <jeff.hugo@oss.qualcomm.com>
Tue, 14 Oct 2025 14:56:31 +0000 (08:56 -0600)
Two threads of the same process can potential read and write parallelly to
head and tail pointers of the same DBC request queue. This could lead to a
race condition and corrupt the DBC request queue.

Fixes: ff13be830333 ("accel/qaic: Add datapath")
Signed-off-by: Pranjal Ramajor Asha Kanojiya <quic_pkanojiy@quicinc.com>
Signed-off-by: Youssef Samir <youssef.abdulrahman@oss.qualcomm.com>
Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Reviewed-by: Carl Vanderlip <carl.vanderlip@oss.qualcomm.com>
[jhugo: Add fixes tag]
Signed-off-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20251007061837.206132-1-youssef.abdulrahman@oss.qualcomm.com
drivers/accel/qaic/qaic.h
drivers/accel/qaic/qaic_data.c
drivers/accel/qaic/qaic_drv.c

index c31081e42cee0a3ac53c05e618bbf36908f4eebf..820d133236dd19ce411a901bb569f6673a0c7d35 100644 (file)
@@ -97,6 +97,8 @@ struct dma_bridge_chan {
         * response queue's head and tail pointer of this DBC.
         */
        void __iomem            *dbc_base;
+       /* Synchronizes access to Request queue's head and tail pointer */
+       struct mutex            req_lock;
        /* Head of list where each node is a memory handle queued in request queue */
        struct list_head        xfer_list;
        /* Synchronizes DBC readers during cleanup */
index 797289e9d780647b3d498622707850b5612e7a49..c4f117edb266ece45634b890938804a15691cf3a 100644 (file)
@@ -1356,13 +1356,17 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr
                goto release_ch_rcu;
        }
 
+       ret = mutex_lock_interruptible(&dbc->req_lock);
+       if (ret)
+               goto release_ch_rcu;
+
        head = readl(dbc->dbc_base + REQHP_OFF);
        tail = readl(dbc->dbc_base + REQTP_OFF);
 
        if (head == U32_MAX || tail == U32_MAX) {
                /* PCI link error */
                ret = -ENODEV;
-               goto release_ch_rcu;
+               goto unlock_req_lock;
        }
 
        queue_level = head <= tail ? tail - head : dbc->nelem - (head - tail);
@@ -1370,11 +1374,12 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr
        ret = send_bo_list_to_device(qdev, file_priv, exec, args->hdr.count, is_partial, dbc,
                                     head, &tail);
        if (ret)
-               goto release_ch_rcu;
+               goto unlock_req_lock;
 
        /* Finalize commit to hardware */
        submit_ts = ktime_get_ns();
        writel(tail, dbc->dbc_base + REQTP_OFF);
+       mutex_unlock(&dbc->req_lock);
 
        update_profiling_data(file_priv, exec, args->hdr.count, is_partial, received_ts,
                              submit_ts, queue_level);
@@ -1382,6 +1387,9 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr
        if (datapath_polling)
                schedule_work(&dbc->poll_work);
 
+unlock_req_lock:
+       if (ret)
+               mutex_unlock(&dbc->req_lock);
 release_ch_rcu:
        srcu_read_unlock(&dbc->ch_lock, rcu_id);
 unlock_dev_srcu:
index e31bcb0ecfc946e1990ebce2a5cba6564a91e8a0..e162f4b8a262abca4ac5e7bd8b187ca2061ad191 100644 (file)
@@ -454,6 +454,9 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev,
                        return NULL;
                init_waitqueue_head(&qdev->dbc[i].dbc_release);
                INIT_LIST_HEAD(&qdev->dbc[i].bo_lists);
+               ret = drmm_mutex_init(drm, &qdev->dbc[i].req_lock);
+               if (ret)
+                       return NULL;
        }
 
        return qdev;