Loading drivers/scsi/ufs/debugfs.c +95 −13 Original line number Diff line number Diff line Loading @@ -753,6 +753,23 @@ out: return ret; } 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); scsi_block_requests(hba->host); ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US); if (!ret) ret = ufshcd_change_power_mode(hba, desired_pwr_mode); scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); return ret; } static ssize_t ufsdbg_power_mode_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) Loading @@ -764,7 +781,6 @@ static ssize_t ufsdbg_power_mode_write(struct file *file, loff_t buff_pos = 0; int ret; int idx = 0; #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ ret = simple_write_to_buffer(pwr_mode_str, BUFF_LINE_CAPACITY, &buff_pos, ubuf, cnt); Loading Loading @@ -800,13 +816,7 @@ static ssize_t ufsdbg_power_mode_write(struct file *file, return cnt; } pm_runtime_get_sync(hba->dev); scsi_block_requests(hba->host); ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US); if (!ret) ret = ufshcd_change_power_mode(hba, &final_pwr_mode); scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); ret = ufsdbg_config_pwr_mode(hba, &final_pwr_mode); if (ret == -EBUSY) dev_err(hba->dev, "%s: ufshcd_config_pwr_mode failed: system is busy, try again\n", Loading @@ -830,19 +840,21 @@ static const struct file_operations ufsdbg_power_mode_desc = { .write = ufsdbg_power_mode_write, }; static int ufsdbg_dme_local_read(void *data, u64 *attr_val) static int ufsdbg_dme_read(void *data, u64 *attr_val, bool peer) { int ret; struct ufs_hba *hba = data; u32 read_val = 0; u32 attr_id, read_val = 0; int (*read_func) (struct ufs_hba *, u32, u32 *); if (!hba) return -EINVAL; read_func = peer ? ufshcd_dme_peer_get : ufshcd_dme_get; 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(hba->debugfs_files.dme_local_attr_id), &read_val); ret = ufshcd_dme_get(hba, UIC_ARG_MIB(attr_id), &read_val); pm_runtime_put_sync(hba->dev); if (!ret) Loading @@ -863,11 +875,70 @@ static int ufsdbg_dme_local_set_attr_id(void *data, u64 attr_id) return 0; } static int ufsdbg_dme_local_read(void *data, u64 *attr_val) { return ufsdbg_dme_read(data, attr_val, false); } DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_local_read_ops, ufsdbg_dme_local_read, ufsdbg_dme_local_set_attr_id, "%llu\n"); 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; } static int ufsdbg_dme_peer_set_attr_id(void *data, u64 attr_id) { struct ufs_hba *hba = data; if (!hba) return -EINVAL; hba->debugfs_files.dme_peer_attr_id = (u32)attr_id; return 0; } DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_peer_read_ops, ufsdbg_dme_peer_read, ufsdbg_dme_peer_set_attr_id, "%llu\n"); void ufsdbg_add_debugfs(struct ufs_hba *hba) { if (!hba) { Loading Loading @@ -962,6 +1033,17 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba) goto err; } hba->debugfs_files.dme_peer_read = debugfs_create_file("dme_peer_read", S_IRUSR | S_IWUSR, hba->debugfs_files.debugfs_root, hba, &ufsdbg_dme_peer_read_ops); if (!hba->debugfs_files.dme_peer_read) { dev_err(hba->dev, "%s: failed create dme_peer_read debugfs entry\n", __func__); goto err; } ufsdbg_setup_fault_injection(hba); return; Loading drivers/scsi/ufs/ufs-qcom.c +2 −0 Original line number Diff line number Diff line Loading @@ -750,6 +750,8 @@ 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); hba->quirks |= UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE; } static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, Loading drivers/scsi/ufs/ufshcd.c +2 −0 Original line number Diff line number Diff line Loading @@ -2705,6 +2705,7 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) bool timeout = false; ktime_t start = ktime_get(); ufshcd_hold(hba, false); spin_lock_irqsave(hba->host->host_lock, flags); if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) { ret = -EBUSY; Loading Loading @@ -2739,6 +2740,7 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) } out: spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_release(hba); return ret; } Loading include/linux/scsi/ufs/ufshcd.h +8 −0 Original line number Diff line number Diff line Loading @@ -240,7 +240,9 @@ struct debugfs_files { struct dentry *dump_dev_desc; struct dentry *power_mode; struct dentry *dme_local_read; struct dentry *dme_peer_read; u32 dme_local_attr_id; u32 dme_peer_attr_id; #ifdef CONFIG_UFS_FAULT_INJECTION struct fault_attr fail_attr; #endif Loading Loading @@ -507,6 +509,12 @@ 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. */ #define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE UFS_BIT(4) unsigned int quirks; /* Deviations from standard UFSHCI spec. */ /* Device deviations from standard UFS device spec. */ Loading Loading
drivers/scsi/ufs/debugfs.c +95 −13 Original line number Diff line number Diff line Loading @@ -753,6 +753,23 @@ out: return ret; } 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); scsi_block_requests(hba->host); ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US); if (!ret) ret = ufshcd_change_power_mode(hba, desired_pwr_mode); scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); return ret; } static ssize_t ufsdbg_power_mode_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) Loading @@ -764,7 +781,6 @@ static ssize_t ufsdbg_power_mode_write(struct file *file, loff_t buff_pos = 0; int ret; int idx = 0; #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */ ret = simple_write_to_buffer(pwr_mode_str, BUFF_LINE_CAPACITY, &buff_pos, ubuf, cnt); Loading Loading @@ -800,13 +816,7 @@ static ssize_t ufsdbg_power_mode_write(struct file *file, return cnt; } pm_runtime_get_sync(hba->dev); scsi_block_requests(hba->host); ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US); if (!ret) ret = ufshcd_change_power_mode(hba, &final_pwr_mode); scsi_unblock_requests(hba->host); pm_runtime_put_sync(hba->dev); ret = ufsdbg_config_pwr_mode(hba, &final_pwr_mode); if (ret == -EBUSY) dev_err(hba->dev, "%s: ufshcd_config_pwr_mode failed: system is busy, try again\n", Loading @@ -830,19 +840,21 @@ static const struct file_operations ufsdbg_power_mode_desc = { .write = ufsdbg_power_mode_write, }; static int ufsdbg_dme_local_read(void *data, u64 *attr_val) static int ufsdbg_dme_read(void *data, u64 *attr_val, bool peer) { int ret; struct ufs_hba *hba = data; u32 read_val = 0; u32 attr_id, read_val = 0; int (*read_func) (struct ufs_hba *, u32, u32 *); if (!hba) return -EINVAL; read_func = peer ? ufshcd_dme_peer_get : ufshcd_dme_get; 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(hba->debugfs_files.dme_local_attr_id), &read_val); ret = ufshcd_dme_get(hba, UIC_ARG_MIB(attr_id), &read_val); pm_runtime_put_sync(hba->dev); if (!ret) Loading @@ -863,11 +875,70 @@ static int ufsdbg_dme_local_set_attr_id(void *data, u64 attr_id) return 0; } static int ufsdbg_dme_local_read(void *data, u64 *attr_val) { return ufsdbg_dme_read(data, attr_val, false); } DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_local_read_ops, ufsdbg_dme_local_read, ufsdbg_dme_local_set_attr_id, "%llu\n"); 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; } static int ufsdbg_dme_peer_set_attr_id(void *data, u64 attr_id) { struct ufs_hba *hba = data; if (!hba) return -EINVAL; hba->debugfs_files.dme_peer_attr_id = (u32)attr_id; return 0; } DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_peer_read_ops, ufsdbg_dme_peer_read, ufsdbg_dme_peer_set_attr_id, "%llu\n"); void ufsdbg_add_debugfs(struct ufs_hba *hba) { if (!hba) { Loading Loading @@ -962,6 +1033,17 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba) goto err; } hba->debugfs_files.dme_peer_read = debugfs_create_file("dme_peer_read", S_IRUSR | S_IWUSR, hba->debugfs_files.debugfs_root, hba, &ufsdbg_dme_peer_read_ops); if (!hba->debugfs_files.dme_peer_read) { dev_err(hba->dev, "%s: failed create dme_peer_read debugfs entry\n", __func__); goto err; } ufsdbg_setup_fault_injection(hba); return; Loading
drivers/scsi/ufs/ufs-qcom.c +2 −0 Original line number Diff line number Diff line Loading @@ -750,6 +750,8 @@ 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); hba->quirks |= UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE; } static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, Loading
drivers/scsi/ufs/ufshcd.c +2 −0 Original line number Diff line number Diff line Loading @@ -2705,6 +2705,7 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) bool timeout = false; ktime_t start = ktime_get(); ufshcd_hold(hba, false); spin_lock_irqsave(hba->host->host_lock, flags); if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) { ret = -EBUSY; Loading Loading @@ -2739,6 +2740,7 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) } out: spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_release(hba); return ret; } Loading
include/linux/scsi/ufs/ufshcd.h +8 −0 Original line number Diff line number Diff line Loading @@ -240,7 +240,9 @@ struct debugfs_files { struct dentry *dump_dev_desc; struct dentry *power_mode; struct dentry *dme_local_read; struct dentry *dme_peer_read; u32 dme_local_attr_id; u32 dme_peer_attr_id; #ifdef CONFIG_UFS_FAULT_INJECTION struct fault_attr fail_attr; #endif Loading Loading @@ -507,6 +509,12 @@ 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. */ #define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE UFS_BIT(4) unsigned int quirks; /* Deviations from standard UFSHCI spec. */ /* Device deviations from standard UFS device spec. */ Loading