From: Pranjal Ramajor Asha Kanojiya <[email protected]>

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.

Signed-off-by: Pranjal Ramajor Asha Kanojiya <[email protected]>
Signed-off-by: Youssef Samir <[email protected]>
---
 drivers/accel/qaic/qaic.h      |  2 ++
 drivers/accel/qaic/qaic_data.c | 12 ++++++++++--
 drivers/accel/qaic/qaic_drv.c  |  3 +++
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h
index c31081e42cee..820d133236dd 100644
--- a/drivers/accel/qaic/qaic.h
+++ b/drivers/accel/qaic/qaic.h
@@ -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 */
diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c
index 797289e9d780..c4f117edb266 100644
--- a/drivers/accel/qaic/qaic_data.c
+++ b/drivers/accel/qaic/qaic_data.c
@@ -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:
diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c
index e31bcb0ecfc9..e162f4b8a262 100644
--- a/drivers/accel/qaic/qaic_drv.c
+++ b/drivers/accel/qaic/qaic_drv.c
@@ -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;
-- 
2.43.0

Reply via email to