156 lines
4.6 KiB
Diff
156 lines
4.6 KiB
Diff
From cf6d321107cbbb91e440395c0a26075e500ed5be Mon Sep 17 00:00:00 2001
|
|
From: Weili Qian <qianweili@huawei.com>
|
|
Date: Thu, 30 Nov 2023 16:41:27 +0800
|
|
Subject: [PATCH 093/123] uadk: check queue status before sending doorbells
|
|
|
|
When the device needs to be reset, the queue status is
|
|
set to disable before resetting. The user process checks
|
|
the queue status before sending the doorbell. If the queue
|
|
is disable, the user process returns failure.
|
|
|
|
Currently, the task execution order in user mode is as follows:
|
|
1. check the queue status.
|
|
2. fill in or parse the BD.
|
|
3. send the doorbell to the hardware.
|
|
|
|
To reduce the possibility of sending doorbells during reset,
|
|
the task execution order is modified as follows:
|
|
1. fill in or parse the BD.
|
|
2. check the queue status.
|
|
3. send the doorbell to the hardware.
|
|
|
|
In addition, a rmb() is added before the doorbell is
|
|
sent to ensure that the queue status check is complete.
|
|
|
|
rmb() and wmb() can be replaced by mb() in hisi_qm_send().
|
|
Therefore, the barrier on the wd_ioread() and wd_iowrite()
|
|
can be deleted.
|
|
|
|
Signed-off-by: Weili Qian <qianweili@huawei.com>
|
|
---
|
|
drv/hisi_qm_udrv.c | 39 ++++++++++++++++++++++++++++-----------
|
|
include/wd.h | 6 ++----
|
|
2 files changed, 30 insertions(+), 15 deletions(-)
|
|
|
|
diff --git a/drv/hisi_qm_udrv.c b/drv/hisi_qm_udrv.c
|
|
index 4c80959..d8b5271 100644
|
|
--- a/drv/hisi_qm_udrv.c
|
|
+++ b/drv/hisi_qm_udrv.c
|
|
@@ -469,11 +469,6 @@ int hisi_qm_send(handle_t h_qp, const void *req, __u16 expect, __u16 *count)
|
|
|
|
q_info = &qp->q_info;
|
|
|
|
- if (unlikely(wd_ioread32(q_info->ds_tx_base) == 1)) {
|
|
- WD_ERR("wd queue hw error happened before qm send!\n");
|
|
- return -WD_HW_EACCESS;
|
|
- }
|
|
-
|
|
pthread_spin_lock(&q_info->sd_lock);
|
|
free_num = get_free_num(q_info);
|
|
if (!free_num) {
|
|
@@ -486,14 +481,26 @@ int hisi_qm_send(handle_t h_qp, const void *req, __u16 expect, __u16 *count)
|
|
tail = q_info->sq_tail_index;
|
|
hisi_qm_fill_sqe(req, q_info, tail, send_num);
|
|
tail = (tail + send_num) % q_info->sq_depth;
|
|
+
|
|
+ /*
|
|
+ * Before sending doorbell, check the queue status,
|
|
+ * if the queue is disable, return failure.
|
|
+ */
|
|
+ if (unlikely(wd_ioread32(q_info->ds_tx_base) == 1)) {
|
|
+ pthread_spin_unlock(&q_info->sd_lock);
|
|
+ WD_DEV_ERR(qp->h_ctx, "wd queue hw error happened before qm send!\n");
|
|
+ return -WD_HW_EACCESS;
|
|
+ }
|
|
+
|
|
+ /* Make sure sqe is filled before db ring and queue status check is complete. */
|
|
+ mb();
|
|
q_info->db(q_info, QM_DBELL_CMD_SQ, tail, 0);
|
|
q_info->sq_tail_index = tail;
|
|
|
|
/* Make sure used_num is changed before the next thread gets free sqe. */
|
|
__atomic_add_fetch(&q_info->used_num, send_num, __ATOMIC_RELAXED);
|
|
- *count = send_num;
|
|
-
|
|
pthread_spin_unlock(&q_info->sd_lock);
|
|
+ *count = send_num;
|
|
|
|
return 0;
|
|
}
|
|
@@ -509,6 +516,8 @@ static int hisi_qm_recv_single(struct hisi_qm_queue_info *q_info, void *resp)
|
|
cqe = q_info->cq_base + i * sizeof(struct cqe);
|
|
|
|
if (q_info->cqc_phase == CQE_PHASE(cqe)) {
|
|
+ /* Make sure cqe valid bit is set */
|
|
+ rmb();
|
|
j = CQE_SQ_HEAD_INDEX(cqe);
|
|
if (unlikely(j >= q_info->sq_depth)) {
|
|
pthread_spin_unlock(&q_info->rv_lock);
|
|
@@ -529,6 +538,18 @@ static int hisi_qm_recv_single(struct hisi_qm_queue_info *q_info, void *resp)
|
|
i++;
|
|
}
|
|
|
|
+ /*
|
|
+ * Before sending doorbell, check the queue status,
|
|
+ * if the queue is disable, return failure.
|
|
+ */
|
|
+ if (unlikely(wd_ioread32(q_info->ds_rx_base) == 1)) {
|
|
+ pthread_spin_unlock(&q_info->rv_lock);
|
|
+ WD_DEV_ERR(qp->h_ctx, "wd queue hw error happened after qm receive!\n");
|
|
+ return -WD_HW_EACCESS;
|
|
+ }
|
|
+
|
|
+ /* Make sure queue status check is complete. */
|
|
+ rmb();
|
|
q_info->db(q_info, QM_DBELL_CMD_CQ, i, q_info->epoll_en);
|
|
|
|
/* only support one thread poll one queue, so no need protect */
|
|
@@ -568,10 +589,6 @@ int hisi_qm_recv(handle_t h_qp, void *resp, __u16 expect, __u16 *count)
|
|
}
|
|
|
|
*count = recv_num;
|
|
- if (unlikely(wd_ioread32(q_info->ds_rx_base) == 1)) {
|
|
- WD_DEV_ERR(qp->h_ctx, "wd queue hw error happened in qm receive!\n");
|
|
- return -WD_HW_EACCESS;
|
|
- }
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/include/wd.h b/include/wd.h
|
|
index 0e67cad..0a654d6 100644
|
|
--- a/include/wd.h
|
|
+++ b/include/wd.h
|
|
@@ -167,7 +167,7 @@ static inline uint32_t wd_ioread32(void *addr)
|
|
uint32_t ret;
|
|
|
|
ret = *((volatile uint32_t *)addr);
|
|
- rmb();
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -176,19 +176,17 @@ static inline uint64_t wd_ioread64(void *addr)
|
|
uint64_t ret;
|
|
|
|
ret = *((volatile uint64_t *)addr);
|
|
- rmb();
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
static inline void wd_iowrite32(void *addr, uint32_t value)
|
|
{
|
|
- wmb();
|
|
*((volatile uint32_t *)addr) = value;
|
|
}
|
|
|
|
static inline void wd_iowrite64(void *addr, uint64_t value)
|
|
{
|
|
- wmb();
|
|
*((volatile uint64_t *)addr) = value;
|
|
}
|
|
|
|
--
|
|
2.31.1.windows.1
|
|
|