mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
BACKPORT: scsi: ufs: mcq: Fix the incorrect OCS value for the device command
In MCQ mode, when a device command uses a hardware queue shared with other commands, a race condition may occur in the following scenario: 1. A device command is completed in CQx with CQE entry "e". 2. The interrupt handler copies the "cqe" pointer to "hba->dev_cmd.cqe" and completes "hba->dev_cmd.complete". 3. The "ufshcd_wait_for_dev_cmd()" function is awakened and retrieves the OCS value from "hba->dev_cmd.cqe". However, there is a possibility that the CQE entry "e" will be overwritten by newly completed commands in CQx, resulting in an incorrect OCS value being received by "ufshcd_wait_for_dev_cmd()". To avoid this race condition, the OCS value should be immediately copied to the struct "lrb" of the device command. Then "ufshcd_wait_for_dev_cmd()" can retrieve the OCS value from the struct "lrb". Bug: 267974767 Fixes:57b1c0ef89("scsi: ufs: core: mcq: Add support to allocate multiple queues") Suggested-by: Can Guo <quic_cang@quicinc.com> Signed-off-by: Stanley Chu <stanley.chu@mediatek.com> Link: https://lore.kernel.org/r/20230610021553.1213-2-powen.kao@mediatek.com Tested-by: Po-Wen Kao <powen.kao@mediatek.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Change-Id: I835e435c8a5fffa63b02bd1481f7b41d2a16e706 (cherry picked from commit0fef6bb730) [powen: Keep hba->dev_cmd.cqe for KMI freeze]
This commit is contained in:
committed by
Matthias Männich
parent
dc64f5f480
commit
2eb4158749
@@ -3166,7 +3166,7 @@ retry:
|
|||||||
* not trigger any race conditions.
|
* not trigger any race conditions.
|
||||||
*/
|
*/
|
||||||
hba->dev_cmd.complete = NULL;
|
hba->dev_cmd.complete = NULL;
|
||||||
err = ufshcd_get_tr_ocs(lrbp, hba->dev_cmd.cqe);
|
err = ufshcd_get_tr_ocs(lrbp, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = ufshcd_dev_cmd_completion(hba, lrbp);
|
err = ufshcd_dev_cmd_completion(hba, lrbp);
|
||||||
} else {
|
} else {
|
||||||
@@ -3262,7 +3262,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hba->dev_cmd.complete = &wait;
|
hba->dev_cmd.complete = &wait;
|
||||||
hba->dev_cmd.cqe = NULL;
|
|
||||||
|
|
||||||
ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
|
ufshcd_add_query_upiu_trace(hba, UFS_QUERY_SEND, lrbp->ucd_req_ptr);
|
||||||
|
|
||||||
@@ -5520,6 +5519,7 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
|
|||||||
{
|
{
|
||||||
struct ufshcd_lrb *lrbp;
|
struct ufshcd_lrb *lrbp;
|
||||||
struct scsi_cmnd *cmd;
|
struct scsi_cmnd *cmd;
|
||||||
|
enum utp_ocs ocs;
|
||||||
|
|
||||||
lrbp = &hba->lrb[task_tag];
|
lrbp = &hba->lrb[task_tag];
|
||||||
lrbp->compl_time_stamp = ktime_get();
|
lrbp->compl_time_stamp = ktime_get();
|
||||||
@@ -5538,7 +5538,11 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag,
|
|||||||
lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
|
lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
|
||||||
if (hba->dev_cmd.complete) {
|
if (hba->dev_cmd.complete) {
|
||||||
trace_android_vh_ufs_compl_command(hba, lrbp);
|
trace_android_vh_ufs_compl_command(hba, lrbp);
|
||||||
hba->dev_cmd.cqe = cqe;
|
if (cqe) {
|
||||||
|
ocs = le32_to_cpu(cqe->status) & MASK_OCS;
|
||||||
|
lrbp->utr_descriptor_ptr->header.dword_2 =
|
||||||
|
cpu_to_le32(ocs);
|
||||||
|
}
|
||||||
ufshcd_add_command_trace(hba, task_tag, UFS_DEV_COMP);
|
ufshcd_add_command_trace(hba, task_tag, UFS_DEV_COMP);
|
||||||
complete(hba->dev_cmd.complete);
|
complete(hba->dev_cmd.complete);
|
||||||
ufshcd_clk_scaling_update_busy(hba);
|
ufshcd_clk_scaling_update_busy(hba);
|
||||||
|
|||||||
Reference in New Issue
Block a user