Per JEDEC UFSHCI (JESD223G Section 6.1.1 and Section 4.4.6 Step 2B), host software in MCQ mode may stop a Submission Queue and nullify an unfetched SQE by setting its UTRD Command Type (DW0 bits 31:28) to 0xF. When the Submission Queue is resumed, the host controller shall skip execution of the nullified transfer request and post a Completion Queue Entry (CQE) to the Completion Queue with OCS = ABORTED (0x06).
In ufs_mcq_process_sq(), check for UFS_UTP_CMD_TYPE_NULL (0xF), read the Request UPIU header on a best-effort basis via ufs_dma_read_req_upiu() to populate cqe.task_tag and cqe.lun for UFSHCI 4.1+ completion decoding, and unconditionally post a CQE with UFS_OCS_ABORTED without executing the command or writing a Response UPIU for the nullified entry. Signed-off-by: Stanley Jhu <[email protected]> --- hw/ufs/ufs.c | 17 ++++++++++++++++- include/block/ufs.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 4c505e0bf..f008af746 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -36,6 +36,7 @@ static void ufs_exec_req(UfsRequest *req); static void ufs_clear_req(UfsRequest *req); +static void ufs_mcq_process_cq(void *opaque); static inline uint64_t ufs_mcq_reg_addr(UfsHc *u, int qid) { @@ -474,6 +475,17 @@ static void ufs_mcq_process_sq(void *opaque) ufs_mcq_init_req(sq->u, req, sq); memcpy(&req->utrd, &sqe, sizeof(req->utrd)); + if ((le32_to_cpu(sqe.header.dword_0) >> 28) == UFS_UTP_CMD_TYPE_NULL) { + ufs_dma_read_req_upiu(req); + req->utrd.header.dword_2 = cpu_to_le32( + (le32_to_cpu(req->utrd.header.dword_2) & ~UFS_MASK_OCS) | + UFS_OCS_ABORTED); + req->state = UFS_REQUEST_COMPLETE; + QTAILQ_INSERT_TAIL(&sq->cq->req_list, req, entry); + ufs_mcq_process_cq(sq->cq); + continue; + } + req->state = UFS_REQUEST_RUNNING; ufs_exec_req(req); } @@ -493,7 +505,10 @@ static void ufs_mcq_process_cq(void *opaque) break; } - ufs_dma_write_rsp_upiu(req); + if ((le32_to_cpu(req->utrd.header.dword_0) >> 28) != + UFS_UTP_CMD_TYPE_NULL) { + ufs_dma_write_rsp_upiu(req); + } /* UTRD/CQE are LE; round-trip through host to keep BE correct. */ uint64_t ucdba = diff --git a/include/block/ufs.h b/include/block/ufs.h index b0515325f..4a614fbe5 100644 --- a/include/block/ufs.h +++ b/include/block/ufs.h @@ -665,6 +665,7 @@ enum { UFS_UTP_CMD_TYPE_SCSI = 0x0, UFS_UTP_CMD_TYPE_UFS = 0x1, UFS_UTP_CMD_TYPE_DEV_MANAGE = 0x2, + UFS_UTP_CMD_TYPE_NULL = 0xf, }; /* To accommodate UFS2.0 required Command type */ -- 2.56.0.rc1.315.gc6ed9934b7-goog
