Loading drivers/scsi/ufs/debugfs.c +9 −31 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ struct desc_field_offset { } \ } while (0) #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ #ifdef CONFIG_UFS_FAULT_INJECTION #define INJECT_COMMAND_HANG (0x0) Loading Loading @@ -756,7 +758,6 @@ out: static int ufsdbg_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode) { #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ int ret; pm_runtime_get_sync(hba->dev); Loading Loading @@ -854,7 +855,11 @@ static int ufsdbg_dme_read(void *data, u64 *attr_val, bool peer) attr_id = peer ? hba->debugfs_files.dme_peer_attr_id : hba->debugfs_files.dme_local_attr_id; pm_runtime_get_sync(hba->dev); ret = ufshcd_dme_get(hba, UIC_ARG_MIB(attr_id), &read_val); scsi_block_requests(hba->host); ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US); if (!ret) ret = read_func(hba, UIC_ARG_MIB(attr_id), &read_val); scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); if (!ret) Loading Loading @@ -887,39 +892,12 @@ DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_local_read_ops, static int ufsdbg_dme_peer_read(void *data, u64 *attr_val) { int ret; struct ufs_hba *hba = data; struct ufs_pa_layer_attr orig_pwr_info; struct ufs_pa_layer_attr temp_pwr_info; bool restore_pwr_mode = false; if (!hba) return -EINVAL; if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) { orig_pwr_info = hba->pwr_info; temp_pwr_info = orig_pwr_info; if (orig_pwr_info.pwr_tx == FAST_MODE || orig_pwr_info.pwr_rx == FAST_MODE) { temp_pwr_info.pwr_tx = FASTAUTO_MODE; temp_pwr_info.pwr_rx = FASTAUTO_MODE; ret = ufsdbg_config_pwr_mode(hba, &temp_pwr_info); if (ret) goto out; else restore_pwr_mode = true; } } ret = ufsdbg_dme_read(data, attr_val, true); if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) { if (restore_pwr_mode) ufsdbg_config_pwr_mode(hba, &orig_pwr_info); } out: return ret; return ufsdbg_dme_read(data, attr_val, true); } static int ufsdbg_dme_peer_set_attr_id(void *data, u64 attr_id) Loading drivers/scsi/ufs/ufs-qcom.c +1 −1 Original line number Diff line number Diff line Loading @@ -764,7 +764,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP | UFSHCD_QUIRK_BROKEN_LCC | UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE); | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE); if ((minor == 0x001) && (step == 0x0001)) hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; Loading drivers/scsi/ufs/ufshcd.c +29 −0 Original line number Diff line number Diff line Loading @@ -2630,6 +2630,31 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, const char *get = action[!!peer]; int ret; int retries = UFS_UIC_COMMAND_RETRIES; struct ufs_pa_layer_attr orig_pwr_info; struct ufs_pa_layer_attr temp_pwr_info; bool pwr_mode_change = false; if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)) { orig_pwr_info = hba->pwr_info; temp_pwr_info = orig_pwr_info; if (orig_pwr_info.pwr_tx == FAST_MODE || orig_pwr_info.pwr_rx == FAST_MODE) { temp_pwr_info.pwr_tx = FASTAUTO_MODE; temp_pwr_info.pwr_rx = FASTAUTO_MODE; pwr_mode_change = true; } else if (orig_pwr_info.pwr_tx == SLOW_MODE || orig_pwr_info.pwr_rx == SLOW_MODE) { temp_pwr_info.pwr_tx = SLOWAUTO_MODE; temp_pwr_info.pwr_rx = SLOWAUTO_MODE; pwr_mode_change = true; } if (pwr_mode_change) { ret = ufshcd_change_power_mode(hba, &temp_pwr_info); if (ret) goto out; } } uic_cmd.command = peer ? UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; Loading @@ -2654,6 +2679,10 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, if (mib_val && !ret) *mib_val = uic_cmd.argument3; if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE) && pwr_mode_change) ufshcd_change_power_mode(hba, &orig_pwr_info); out: return ret; } EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr); Loading include/linux/scsi/ufs/ufshcd.h +4 −3 Original line number Diff line number Diff line Loading @@ -510,10 +510,11 @@ struct ufs_hba { #define UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP UFS_BIT(3) /* * This quirk needs to be enabled if the host contoller doesn't * allow reading the dme attributes of peer UniPro in FAST_MODE. * This quirk needs to be enabled if the host contoller only allows * accessing the peer dme attributes in AUTO mode (FAST AUTO or * SLOW AUTO). */ #define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE UFS_BIT(4) #define UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE UFS_BIT(4) unsigned int quirks; /* Deviations from standard UFSHCI spec. */ Loading Loading
drivers/scsi/ufs/debugfs.c +9 −31 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ struct desc_field_offset { } \ } while (0) #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ #ifdef CONFIG_UFS_FAULT_INJECTION #define INJECT_COMMAND_HANG (0x0) Loading Loading @@ -756,7 +758,6 @@ out: static int ufsdbg_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode) { #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ int ret; pm_runtime_get_sync(hba->dev); Loading Loading @@ -854,7 +855,11 @@ static int ufsdbg_dme_read(void *data, u64 *attr_val, bool peer) attr_id = peer ? hba->debugfs_files.dme_peer_attr_id : hba->debugfs_files.dme_local_attr_id; pm_runtime_get_sync(hba->dev); ret = ufshcd_dme_get(hba, UIC_ARG_MIB(attr_id), &read_val); scsi_block_requests(hba->host); ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US); if (!ret) ret = read_func(hba, UIC_ARG_MIB(attr_id), &read_val); scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); if (!ret) Loading Loading @@ -887,39 +892,12 @@ DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_local_read_ops, static int ufsdbg_dme_peer_read(void *data, u64 *attr_val) { int ret; struct ufs_hba *hba = data; struct ufs_pa_layer_attr orig_pwr_info; struct ufs_pa_layer_attr temp_pwr_info; bool restore_pwr_mode = false; if (!hba) return -EINVAL; if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) { orig_pwr_info = hba->pwr_info; temp_pwr_info = orig_pwr_info; if (orig_pwr_info.pwr_tx == FAST_MODE || orig_pwr_info.pwr_rx == FAST_MODE) { temp_pwr_info.pwr_tx = FASTAUTO_MODE; temp_pwr_info.pwr_rx = FASTAUTO_MODE; ret = ufsdbg_config_pwr_mode(hba, &temp_pwr_info); if (ret) goto out; else restore_pwr_mode = true; } } ret = ufsdbg_dme_read(data, attr_val, true); if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) { if (restore_pwr_mode) ufsdbg_config_pwr_mode(hba, &orig_pwr_info); } out: return ret; return ufsdbg_dme_read(data, attr_val, true); } static int ufsdbg_dme_peer_set_attr_id(void *data, u64 attr_id) Loading
drivers/scsi/ufs/ufs-qcom.c +1 −1 Original line number Diff line number Diff line Loading @@ -764,7 +764,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP | UFSHCD_QUIRK_BROKEN_LCC | UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE); | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE); if ((minor == 0x001) && (step == 0x0001)) hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; Loading
drivers/scsi/ufs/ufshcd.c +29 −0 Original line number Diff line number Diff line Loading @@ -2630,6 +2630,31 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, const char *get = action[!!peer]; int ret; int retries = UFS_UIC_COMMAND_RETRIES; struct ufs_pa_layer_attr orig_pwr_info; struct ufs_pa_layer_attr temp_pwr_info; bool pwr_mode_change = false; if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)) { orig_pwr_info = hba->pwr_info; temp_pwr_info = orig_pwr_info; if (orig_pwr_info.pwr_tx == FAST_MODE || orig_pwr_info.pwr_rx == FAST_MODE) { temp_pwr_info.pwr_tx = FASTAUTO_MODE; temp_pwr_info.pwr_rx = FASTAUTO_MODE; pwr_mode_change = true; } else if (orig_pwr_info.pwr_tx == SLOW_MODE || orig_pwr_info.pwr_rx == SLOW_MODE) { temp_pwr_info.pwr_tx = SLOWAUTO_MODE; temp_pwr_info.pwr_rx = SLOWAUTO_MODE; pwr_mode_change = true; } if (pwr_mode_change) { ret = ufshcd_change_power_mode(hba, &temp_pwr_info); if (ret) goto out; } } uic_cmd.command = peer ? UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; Loading @@ -2654,6 +2679,10 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, if (mib_val && !ret) *mib_val = uic_cmd.argument3; if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE) && pwr_mode_change) ufshcd_change_power_mode(hba, &orig_pwr_info); out: return ret; } EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr); Loading
include/linux/scsi/ufs/ufshcd.h +4 −3 Original line number Diff line number Diff line Loading @@ -510,10 +510,11 @@ struct ufs_hba { #define UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP UFS_BIT(3) /* * This quirk needs to be enabled if the host contoller doesn't * allow reading the dme attributes of peer UniPro in FAST_MODE. * This quirk needs to be enabled if the host contoller only allows * accessing the peer dme attributes in AUTO mode (FAST AUTO or * SLOW AUTO). */ #define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE UFS_BIT(4) #define UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE UFS_BIT(4) unsigned int quirks; /* Deviations from standard UFSHCI spec. */ Loading