From bd4a84253c5edcd9224af565d9cb0089c63c4d5b Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Wed, 4 Aug 2021 20:21:27 +0200 Subject: [PATCH] UPSTREAM: core: Add L2P entry swap quirk for Micron UFS For Micron UFS devices the L2P entry need to be byteswapped before sending an HPB READ command to the UFS device. Add the quirk UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ to address this. Link: https://lore.kernel.org/r/20210804182128.458356-2-huobean@gmail.com Reviewed-by: Avri Altman Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen (cherry picked from commit 63522bf3aced0a782b59f0314dbad5cdc8b14c59) Signed-off-by: Luca Porzio Change-Id: I69cfa43c5439e8cace4fe5b2760a38b43d734621 Signed-off-by: Bart Van Assche --- drivers/scsi/ufs/ufs_quirks.h | 6 ++++++ drivers/scsi/ufs/ufshcd.c | 3 ++- drivers/scsi/ufs/ufshpb.c | 15 ++++++++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 07f559ac5883..35ec9ea79869 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -116,4 +116,10 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM (1 << 11) +/* + * Some UFS devices require L2P entry should be swapped before being sent to the + * UFS device for HPB READ command. + */ +#define UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ (1 << 12) + #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e161805fe136..cede7163b8d8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -202,7 +202,8 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state, static struct ufs_dev_fix ufs_fixups[] = { /* UFS cards deviations table */ UFS_FIX(UFS_VENDOR_MICRON, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), + UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM | + UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ), UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM | UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE | diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index 10d8b3dde976..3cce91d1e63f 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -329,15 +329,19 @@ ufshpb_get_pos_from_lpn(struct ufshpb_lu *hpb, unsigned long lpn, int *rgn_idx, } static void -ufshpb_set_hpb_read_to_upiu(struct ufshpb_lu *hpb, struct ufshcd_lrb *lrbp, - u32 lpn, __be64 ppn, u8 transfer_len, int read_id) +ufshpb_set_hpb_read_to_upiu(struct ufs_hba *hba, struct ufshpb_lu *hpb, + struct ufshcd_lrb *lrbp, u32 lpn, __be64 ppn, + u8 transfer_len, int read_id) { unsigned char *cdb = lrbp->cmd->cmnd; - + __be64 ppn_tmp = ppn; cdb[0] = UFSHPB_READ; + if (hba->dev_quirks & UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ) + ppn_tmp = swab64(ppn); + /* ppn value is stored as big-endian in the host memory */ - memcpy(&cdb[6], &ppn, sizeof(__be64)); + memcpy(&cdb[6], &ppn_tmp, sizeof(__be64)); cdb[14] = transfer_len; cdb[15] = read_id; @@ -696,7 +700,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) } } - ufshpb_set_hpb_read_to_upiu(hpb, lrbp, lpn, ppn, transfer_len, read_id); + ufshpb_set_hpb_read_to_upiu(hba, hpb, lrbp, lpn, ppn, transfer_len, + read_id); hpb->stats.hit_cnt++; return 0;