From f04f8628d308b638635a672d8a5ea623b47de773 Mon Sep 17 00:00:00 2001 From: zhucc2 Date: Fri, 8 Oct 2021 12:51:14 +0800 Subject: [PATCH] ufs: Add Micron UFS HID support As Micron said, Micron UFS HID could reuse SamSung HID driver, but need change some flags and attibutes definitions. Change-Id: If485cd01b6b69f1f14947fe84520c190262d966f Reviewed-on: https://gerrit.mot.com/2085180 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Dongliang Yue Reviewed-by: Huosheng Liao Submit-Approved: Jira Key --- drivers/scsi/ufs/Kconfig | 8 +- drivers/scsi/ufs/ufs.h | 7 ++ drivers/scsi/ufs/ufshid.c | 218 +++++++++++++++++++++++++++++--------- drivers/scsi/ufs/ufshid.h | 14 +++ 4 files changed, 193 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index fbb422dfb846..b9a0f6728fd5 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -269,10 +269,16 @@ config SCSI_SKHID bool "UFS Host Initiated Defrag supportr" depends on (SCSI_UFSHCD || SCSI_UFSHCD_QTI) help - Activate or deactive SKHPB driver + Activate or deactive SKHID driver config MICRON_HPB bool "Activate micron HPB Host-aware Performance Booster" depends on SCSI_UFSHCD && UFSFEATURE && UFSHPB help Activate or deactive micron HPB driver + +config MICRON_UFSHID + bool "UFS Host Initiated Defrag supportr" + depends on (SCSI_UFSHCD || SCSI_UFSHCD_QTI) + help + Activate or deactive micron hid driver diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index dfe046fd8f3d..c2ba85d07aa8 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -160,6 +160,9 @@ enum flag_idn { QUERY_FLAG_IDN_TW_BUF_FLUSH_EN = 0x0F, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN = 0x10, #endif +#if defined(CONFIG_MICRON_UFSHID) + QUERY_FLAG_IDN_HID_EN = 0x13 +#endif }; /* Attribute idn for Query requests */ @@ -210,6 +213,10 @@ enum attr_idn { #if defined(CONFIG_UFSFEATURE) QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS = 0xFF, #endif +#if defined(CONFIG_MICRON_UFSHID) + QUERY_ATTR_IDN_HID_FRAG_STATUS = 0x31, + QUERY_ATTR_IDN_HID_PROGRESS = 0x32, +#endif }; #define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02 diff --git a/drivers/scsi/ufs/ufshid.c b/drivers/scsi/ufs/ufshid.c index 1f10b9f53a99..acb33f5d5013 100755 --- a/drivers/scsi/ufs/ufshid.c +++ b/drivers/scsi/ufs/ufshid.c @@ -113,6 +113,54 @@ err_out: return ret; } +#if defined(CONFIG_MICRON_UFSHID) +static int ufshid_set_flag(struct ufshid_dev *hid, u8 idn) +{ + struct ufs_hba *hba = hid->ufsf->hba; + int ret = 0; + bool flag_result; + pm_runtime_get_sync(hba->dev); + + ret = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, idn, 0, + &flag_result); + + if (ret) { + ERR_MSG("set flag [0x%.2X] fail. (%d)", idn, ret); + goto err_out; + } + + HID_DEBUG(hid, "hid_flag set [0x%.2X] result [0x%.2X] ", idn, flag_result); +err_out: + pm_runtime_mark_last_busy(hba->dev); + pm_runtime_put_noidle(hba->dev); + + return ret; +} + +static int ufshid_clear_flag(struct ufshid_dev *hid, u8 idn) +{ + struct ufs_hba *hba = hid->ufsf->hba; + int ret = 0; + + pm_runtime_get_sync(hba->dev); + + ret = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, idn, 0, + NULL); + if (ret) { + ERR_MSG("clear flag [0x%.2X] fail. (%d)", idn, ret); + goto err_out; + } + + HID_DEBUG(hid, "hid_flag set [0x%.2X] ", idn); +err_out: + pm_runtime_mark_last_busy(hba->dev); + pm_runtime_put_noidle(hba->dev); + + return ret; +} +#endif + + static inline int ufshid_version_check(int spec_version) { INFO_MSG("Support HID Spec : Driver = (%.4x), Device = (%.4x)", @@ -133,18 +181,27 @@ void ufshid_get_dev_info(struct ufsf_feature *ufsf, u8 *desc_buf) ufsf->hid_dev = NULL; - if (!(LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP]) & - UFS_FEATURE_SUPPORT_HID_BIT)) { - INFO_MSG("bUFSExFeaturesSupport: HID not support"); - goto err_out; + if(IS_SAMSUNG_DEVICE(storage_mfrid)) { + if (!(LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP]) & + UFS_FEATURE_SUPPORT_HID_BIT)) { + INFO_MSG("bUFSExFeaturesSupport: HID not support"); + goto err_out; + } + + INFO_MSG("bUFSExFeaturesSupport: HID support"); + spec_version = + LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_HID_VER]); + ret = ufshid_version_check(spec_version); + if (ret) + goto err_out; } - INFO_MSG("bUFSExFeaturesSupport: HID support"); - spec_version = - LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_HID_VER]); - ret = ufshid_version_check(spec_version); - if (ret) +#ifndef CONFIG_MICRON_UFSHID + if(IS_MICRON_DEVICE(storage_mfrid)){ + INFO_MSG("micron: HID not support"); goto err_out; + } +#endif ufsf->hid_dev = kzalloc(sizeof(struct ufshid_dev), GFP_KERNEL); if (!ufsf->hid_dev) { @@ -163,39 +220,79 @@ static int ufshid_get_analyze_and_issue_execute(struct ufshid_dev *hid) u32 attr_val; int frag_level; - if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, - HID_OP_EXECUTE)) + if(IS_MICRON_DEVICE(storage_mfrid)) { + #if defined(CONFIG_MICRON_UFSHID) + //get micron ufs frag level + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_STATUS, &frag_level)) + return -EINVAL; + //get micron ufs hid execution progress + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_PROGRESS, &attr_val)) + return -EINVAL; + HID_DEBUG(hid, "micron frag_level= %d attr_val= %d",frag_level,attr_val); + + if (attr_val != HID_PROG_ONGOING) { + if(frag_level!= HID_LEV_GREEN_MICRON) { + ufshid_set_flag(hid, QUERY_FLAG_IDN_HID_EN); + return HID_REQUIRED; + } else { + return HID_NOT_REQUIRED; + } + } else { + return HID_REQUIRED; + } + #else + return HID_NOT_REQUIRED; + #endif + } else if(IS_SAMSUNG_DEVICE(storage_mfrid)) { + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, + HID_OP_EXECUTE)) + return -EINVAL; + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) + return -EINVAL; + + frag_level = attr_val & HID_FRAG_LEVEL_MASK; + HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d", + frag_level, HID_FRAG_UPDATE_STAT(attr_val), + HID_EXECUTE_REQ_STAT(attr_val)); + + if (frag_level == HID_LEV_GRAY) + return -EAGAIN; + + return (HID_EXECUTE_REQ_STAT(attr_val)) ? + HID_REQUIRED : HID_NOT_REQUIRED; + } else { return -EINVAL; - if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) - return -EINVAL; - - frag_level = attr_val & HID_FRAG_LEVEL_MASK; - HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d", - frag_level, HID_FRAG_UPDATE_STAT(attr_val), - HID_EXECUTE_REQ_STAT(attr_val)); - - if (frag_level == HID_LEV_GRAY) - return -EAGAIN; - - return (HID_EXECUTE_REQ_STAT(attr_val)) ? - HID_REQUIRED : HID_NOT_REQUIRED; + } } static int ufshid_issue_disable(struct ufshid_dev *hid) { u32 attr_val; - if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, - HID_OP_DISABLE)) - return -EINVAL; - if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) - return -EINVAL; + if(IS_MICRON_DEVICE(storage_mfrid)) { + #if defined(CONFIG_MICRON_UFSHID) + //get micron ufs hid execution progress + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_PROGRESS, &attr_val)) + return -EINVAL; + HID_DEBUG(hid, "micron hid progress = %d",attr_val); - HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d", - attr_val & HID_FRAG_LEVEL_MASK, - HID_FRAG_UPDATE_STAT(attr_val), - HID_EXECUTE_REQ_STAT(attr_val)); + if(attr_val == HID_PROG_ONGOING) { + if (ufshid_clear_flag(hid, QUERY_FLAG_IDN_HID_EN)) + return -EINVAL; + } + #endif + }else if(IS_SAMSUNG_DEVICE(storage_mfrid)) { + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, + HID_OP_DISABLE)) + return -EINVAL; + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) + return -EINVAL; + HID_DEBUG(hid, "Frag_lv %d Freg_stat %d HID_need_exec %d", + attr_val & HID_FRAG_LEVEL_MASK, + HID_FRAG_UPDATE_STAT(attr_val), + HID_EXECUTE_REQ_STAT(attr_val)); + } return 0; } @@ -706,27 +803,42 @@ static ssize_t ufshid_sysfs_show_color(struct ufshid_dev *hid, char *buf) u32 attr_val; int frag_level; - if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, - HID_OP_ANALYZE)) { - ERR_MSG("query HID_OPERATION fail"); - return -EINVAL; + if(IS_MICRON_DEVICE(storage_mfrid)){ + #if defined(CONFIG_MICRON_UFSHID) + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_STATUS, &attr_val)) + return -EINVAL; + frag_level = attr_val; + /*Micron only has two levels RED & GREEN*/ + return snprintf(buf, PAGE_SIZE, "%s\n", + ((frag_level == HID_LEV_GREEN_MICRON)) ? "GREEN" : + ((frag_level ==HID_LEV_RED_MICRON))?"RED":"UNKNOWN"); + + return snprintf(buf, PAGE_SIZE, "%s\n","Error."); + #endif + } else if(IS_SAMSUNG_DEVICE(storage_mfrid)) { + if (ufshid_write_attr(hid, QUERY_ATTR_IDN_HID_OPERATION, + HID_OP_ANALYZE)) { + ERR_MSG("query HID_OPERATION fail"); + return -EINVAL; + } + + if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) { + ERR_MSG("query HID_FRAG_LEVEL fail"); + return -EINVAL; + } + + frag_level = attr_val & HID_FRAG_LEVEL_MASK; + INFO_MSG("Frag_lv %d Freg_stat %d HID_need_exec %d", frag_level, + HID_FRAG_UPDATE_STAT(attr_val), + HID_EXECUTE_REQ_STAT(attr_val)); + + return snprintf(buf, PAGE_SIZE, "%s\n", + frag_level == HID_LEV_RED ? "RED" : + frag_level == HID_LEV_YELLOW ? "YELLOW" : + frag_level == HID_LEV_GREEN ? "GREEN" : + frag_level == HID_LEV_GRAY ? "GRAY" : "UNKNOWN"); } - - if (ufshid_read_attr(hid, QUERY_ATTR_IDN_HID_FRAG_LEVEL, &attr_val)) { - ERR_MSG("query HID_FRAG_LEVEL fail"); - return -EINVAL; - } - - frag_level = attr_val & HID_FRAG_LEVEL_MASK; - INFO_MSG("Frag_lv %d Freg_stat %d HID_need_exec %d", frag_level, - HID_FRAG_UPDATE_STAT(attr_val), - HID_EXECUTE_REQ_STAT(attr_val)); - - return snprintf(buf, PAGE_SIZE, "%s\n", - frag_level == HID_LEV_RED ? "RED" : - frag_level == HID_LEV_YELLOW ? "YELLOW" : - frag_level == HID_LEV_GREEN ? "GREEN" : - frag_level == HID_LEV_GRAY ? "GRAY" : "UNKNOWN"); + return -EINVAL; } #if defined(CONFIG_UFSHID_POC) diff --git a/drivers/scsi/ufs/ufshid.h b/drivers/scsi/ufs/ufshid.h index 849822ed5121..10a2989cd435 100755 --- a/drivers/scsi/ufs/ufshid.h +++ b/drivers/scsi/ufs/ufshid.h @@ -103,6 +103,20 @@ enum { HID_LEV_RED = 3, }; +#if defined(CONFIG_MICRON_UFSHID) +enum { + HID_LEV_GREEN_MICRON = 0, + HID_LEV_RED_MICRON = 1, +}; + +enum { + HID_PROG_IDLE = 0, + HID_PROG_ONGOING = 1, + HID_PROG_STOP = 2, //stopped by Host + HID_PROG_COMPLETE = 3, +}; +#endif + struct ufshid_dev { struct ufsf_feature *ufsf;