From 4f6dd2a4bf378bc4d169296739ea7d6972c0d858 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Wed, 1 Nov 2023 18:58:36 -0700 Subject: scsi: ufs: ufs-sysfs: Expose UFS power info Having UFS power info available in sysfs makes it easier to tell the state of the link during runtime considering we have a bunch of power saving features and various combinations for backward compatibility. Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bean Huo Reviewed-by: Bart Van Assche Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1698890324-7374-1-git-send-email-quic_cang@quicinc.com Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index c95906443d5f..05b10ca90b50 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -7,9 +7,56 @@ #include #include +#include #include "ufs-sysfs.h" #include "ufshcd-priv.h" +static const char *ufs_pa_pwr_mode_to_string(enum ufs_pa_pwr_mode mode) +{ + switch (mode) { + case FAST_MODE: return "FAST_MODE"; + case SLOW_MODE: return "SLOW_MODE"; + case FASTAUTO_MODE: return "FASTAUTO_MODE"; + case SLOWAUTO_MODE: return "SLOWAUTO_MODE"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_hs_gear_rate_to_string(enum ufs_hs_gear_rate rate) +{ + switch (rate) { + case PA_HS_MODE_A: return "HS_RATE_A"; + case PA_HS_MODE_B: return "HS_RATE_B"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_pwm_gear_to_string(enum ufs_pwm_gear_tag gear) +{ + switch (gear) { + case UFS_PWM_G1: return "PWM_GEAR1"; + case UFS_PWM_G2: return "PWM_GEAR2"; + case UFS_PWM_G3: return "PWM_GEAR3"; + case UFS_PWM_G4: return "PWM_GEAR4"; + case UFS_PWM_G5: return "PWM_GEAR5"; + case UFS_PWM_G6: return "PWM_GEAR6"; + case UFS_PWM_G7: return "PWM_GEAR7"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear) +{ + switch (gear) { + case UFS_HS_G1: return "HS_GEAR1"; + case UFS_HS_G2: return "HS_GEAR2"; + case UFS_HS_G3: return "HS_GEAR3"; + case UFS_HS_G4: return "HS_GEAR4"; + case UFS_HS_G5: return "HS_GEAR5"; + default: return "UNKNOWN"; + } +} + static const char *ufshcd_uic_link_state_to_string( enum uic_link_state state) { @@ -628,6 +675,78 @@ static const struct attribute_group ufs_sysfs_monitor_group = { .attrs = ufs_sysfs_monitor_attrs, }; +static ssize_t lane_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", hba->pwr_info.lane_rx); +} + +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufs_pa_pwr_mode_to_string(hba->pwr_info.pwr_rx)); +} + +static ssize_t rate_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufs_hs_gear_rate_to_string(hba->pwr_info.hs_rate)); +} + +static ssize_t gear_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", hba->pwr_info.hs_rate ? + ufs_hs_gear_to_string(hba->pwr_info.gear_rx) : + ufs_pwm_gear_to_string(hba->pwr_info.gear_rx)); +} + +static ssize_t dev_pm_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufshcd_ufs_dev_pwr_mode_to_string(hba->curr_dev_pwr_mode)); +} + +static ssize_t link_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufshcd_uic_link_state_to_string(hba->uic_link_state)); +} + +static DEVICE_ATTR_RO(lane); +static DEVICE_ATTR_RO(mode); +static DEVICE_ATTR_RO(rate); +static DEVICE_ATTR_RO(gear); +static DEVICE_ATTR_RO(dev_pm); +static DEVICE_ATTR_RO(link_state); + +static struct attribute *ufs_power_info_attrs[] = { + &dev_attr_lane.attr, + &dev_attr_mode.attr, + &dev_attr_rate.attr, + &dev_attr_gear.attr, + &dev_attr_dev_pm.attr, + &dev_attr_link_state.attr, + NULL +}; + +static const struct attribute_group ufs_sysfs_power_info_group = { + .name = "power_info", + .attrs = ufs_power_info_attrs, +}; + static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, u8 desc_index, @@ -1233,6 +1352,7 @@ static const struct attribute_group *ufs_sysfs_groups[] = { &ufs_sysfs_default_group, &ufs_sysfs_capabilities_group, &ufs_sysfs_monitor_group, + &ufs_sysfs_power_info_group, &ufs_sysfs_device_descriptor_group, &ufs_sysfs_interconnect_descriptor_group, &ufs_sysfs_geometry_descriptor_group, -- cgit From 045da3077bc57e587d0ab4cfc8945b76af03d72d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 18 Nov 2023 21:44:43 +0900 Subject: scsi: ufs: core: Make fault injection dynamically configurable per HBA The UFS driver has two driver-specific fault injection mechanisms (trigger_eh and timeout). Each fault injection configuration can only be specified by a module parameter and cannot be reconfigured without reloading the driver. Also, each configuration is common to all HBAs. This change adds the following subdirectories for each UFS HBA when debugfs is enabled: /sys/kernel/debug/ufshcd//timeout_inject /sys/kernel/debug/ufshcd//trigger_eh_inject Each fault injection attribute can be dynamically set per HBA by a corresponding file in these directories. This is tested with QEMU UFS devices. Signed-off-by: Akinobu Mita Link: https://lore.kernel.org/r/20231118124443.1007116-1-akinobu.mita@gmail.com Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-fault-injection.c | 19 +++++++++++++++---- drivers/ufs/core/ufs-fault-injection.h | 13 +++++++++---- drivers/ufs/core/ufshcd.c | 5 +++-- 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufs-fault-injection.c b/drivers/ufs/core/ufs-fault-injection.c index 5b1184aac585..169540417079 100644 --- a/drivers/ufs/core/ufs-fault-injection.c +++ b/drivers/ufs/core/ufs-fault-injection.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "ufs-fault-injection.h" static int ufs_fault_get(char *buffer, const struct kernel_param *kp); @@ -59,12 +60,22 @@ static int ufs_fault_set(const char *val, const struct kernel_param *kp) return 0; } -bool ufs_trigger_eh(void) +void ufs_fault_inject_hba_init(struct ufs_hba *hba) { - return should_fail(&ufs_trigger_eh_attr, 1); + hba->trigger_eh_attr = ufs_trigger_eh_attr; + hba->timeout_attr = ufs_timeout_attr; +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + fault_create_debugfs_attr("trigger_eh_inject", hba->debugfs_root, &hba->trigger_eh_attr); + fault_create_debugfs_attr("timeout_inject", hba->debugfs_root, &hba->timeout_attr); +#endif } -bool ufs_fail_completion(void) +bool ufs_trigger_eh(struct ufs_hba *hba) { - return should_fail(&ufs_timeout_attr, 1); + return should_fail(&hba->trigger_eh_attr, 1); +} + +bool ufs_fail_completion(struct ufs_hba *hba) +{ + return should_fail(&hba->timeout_attr, 1); } diff --git a/drivers/ufs/core/ufs-fault-injection.h b/drivers/ufs/core/ufs-fault-injection.h index 6d0cd8e10c87..996a35769781 100644 --- a/drivers/ufs/core/ufs-fault-injection.h +++ b/drivers/ufs/core/ufs-fault-injection.h @@ -7,15 +7,20 @@ #include #ifdef CONFIG_SCSI_UFS_FAULT_INJECTION -bool ufs_trigger_eh(void); -bool ufs_fail_completion(void); +void ufs_fault_inject_hba_init(struct ufs_hba *hba); +bool ufs_trigger_eh(struct ufs_hba *hba); +bool ufs_fail_completion(struct ufs_hba *hba); #else -static inline bool ufs_trigger_eh(void) +static inline void ufs_fault_inject_hba_init(struct ufs_hba *hba) +{ +} + +static inline bool ufs_trigger_eh(struct ufs_hba *hba) { return false; } -static inline bool ufs_fail_completion(void) +static inline bool ufs_fail_completion(struct ufs_hba *hba) { return false; } diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 8b1031fb0a44..63f0ee117399 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2992,7 +2992,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ufshcd_send_command(hba, tag, hwq); out: - if (ufs_trigger_eh()) { + if (ufs_trigger_eh(hba)) { unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); @@ -5649,7 +5649,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR)) ufshcd_reset_intr_aggr(hba); - if (ufs_fail_completion()) + if (ufs_fail_completion(hba)) return IRQ_HANDLED; /* @@ -9348,6 +9348,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) goto out_disable_vreg; ufs_debugfs_hba_init(hba); + ufs_fault_inject_hba_init(hba); hba->is_powered = true; goto out; -- cgit From db80df77025ee0a5e6e089cc2f2b0c4b97867bea Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Nov 2023 11:33:47 -0800 Subject: scsi: ufs: core: Warn if the request tag is truncated ufshcd_prepare_utp_scsi_cmd_upiu() only uses the lowest eight bits of lrbp->task_tag. Issue a runtime warning if this results in truncation. Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20231115193359.2262044-1-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 63f0ee117399..f0b837cb0c2b 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -2720,6 +2720,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) .command_set_type = UPIU_COMMAND_SET_TYPE_SCSI, }; + WARN_ON_ONCE(ucd_req_ptr->header.task_tag != lrbp->task_tag); + ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(cmd->sdb.length); cdb_len = min_t(unsigned short, cmd->cmd_len, UFS_CDB_SIZE); -- cgit From fa3dca8251c4fff88da9f64ba931942638ab0c00 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:07 -0800 Subject: scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params Structure ufs_dev_params is actually used in UFS host drivers to declare host specific power mode parameters, like ufs__params or host_cap, which makes the code not very straightforward to read. Rename the structure ufs_dev_params to ufs_host_params and unify the declarations in all drivers to host_params. In addition, rename the two functions ufshcd_init_pwr_dev_param() and ufshcd_get_pwr_dev_param() which work based on the ufs_host_params to ufshcd_init_host_params() and ufshcd_negotiate_pwr_params() respectively to avoid confusions. This change does not change any functionalities or logic. Acked-by: Andrew Halaney Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Reviewed-by: Bart Van Assche Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-2-git-send-email-quic_cang@quicinc.com Reviewed-by: Peter Wang Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-exynos.c | 7 ++-- drivers/ufs/host/ufs-hisi.c | 11 +++---- drivers/ufs/host/ufs-mediatek.c | 12 +++---- drivers/ufs/host/ufs-qcom.c | 12 +++---- drivers/ufs/host/ufshcd-pltfrm.c | 69 ++++++++++++++++++++-------------------- drivers/ufs/host/ufshcd-pltfrm.h | 10 +++--- 6 files changed, 57 insertions(+), 64 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 71bd6dbc0547..734d40f99e31 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -765,7 +765,7 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, { struct exynos_ufs *ufs = ufshcd_get_variant(hba); struct phy *generic_phy = ufs->phy; - struct ufs_dev_params ufs_exynos_cap; + struct ufs_host_params host_params; int ret; if (!dev_req_params) { @@ -774,10 +774,9 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, goto out; } - ufshcd_init_pwr_dev_param(&ufs_exynos_cap); + ufshcd_init_host_params(&host_params); - ret = ufshcd_get_pwr_dev_param(&ufs_exynos_cap, - dev_max_params, dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_err("%s: failed to determine capabilities\n", __func__); goto out; diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c index 0229ac0a8dbe..5ee73ff05251 100644 --- a/drivers/ufs/host/ufs-hisi.c +++ b/drivers/ufs/host/ufs-hisi.c @@ -293,9 +293,9 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba, return err; } -static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) +static void ufs_hisi_set_dev_cap(struct ufs_host_params *host_params) { - ufshcd_init_pwr_dev_param(hisi_param); + ufshcd_init_host_params(host_params); } static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) @@ -365,7 +365,7 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { - struct ufs_dev_params ufs_hisi_cap; + struct ufs_host_params host_params; int ret = 0; if (!dev_req_params) { @@ -377,9 +377,8 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufs_hisi_set_dev_cap(&ufs_hisi_cap); - ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap, - dev_max_params, dev_req_params); + ufs_hisi_set_dev_cap(&host_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index fc61790d289b..776bca4f70c8 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -996,16 +996,14 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - struct ufs_dev_params host_cap; + struct ufs_host_params host_params; int ret; - ufshcd_init_pwr_dev_param(&host_cap); - host_cap.hs_rx_gear = UFS_HS_G5; - host_cap.hs_tx_gear = UFS_HS_G5; + ufshcd_init_host_params(&host_params); + host_params.hs_rx_gear = UFS_HS_G5; + host_params.hs_tx_gear = UFS_HS_G5; - ret = ufshcd_get_pwr_dev_param(&host_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_info("%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 96cb8b5b4e66..197c5a5ab136 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -898,7 +898,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_dev_params ufs_qcom_cap; + struct ufs_host_params host_params; int ret = 0; if (!dev_req_params) { @@ -908,15 +908,13 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufshcd_init_pwr_dev_param(&ufs_qcom_cap); - ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE; + ufshcd_init_host_params(&host_params); + host_params.hs_rate = UFS_QCOM_LIMIT_HS_RATE; /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ - ufs_qcom_cap.hs_tx_gear = ufs_qcom_cap.hs_rx_gear = ufs_qcom_get_hs_gear(hba); + host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba); - ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index da2558e274b4..1633edc65689 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -285,61 +285,60 @@ static int ufshcd_parse_operating_points(struct ufs_hba *hba) } /** - * ufshcd_get_pwr_dev_param - get finally agreed attributes for - * power mode change - * @pltfrm_param: pointer to platform parameters + * ufshcd_negotiate_pwr_params - find power mode settings that are supported by + both the controller and the device + * @host_params: pointer to host parameters * @dev_max: pointer to device attributes * @agreed_pwr: returned agreed attributes * * Return: 0 on success, non-zero value on failure. */ -int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, - const struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) +int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, + const struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) { - int min_pltfrm_gear; + int min_host_gear; int min_dev_gear; bool is_dev_sup_hs = false; - bool is_pltfrm_max_hs = false; + bool is_host_max_hs = false; if (dev_max->pwr_rx == FAST_MODE) is_dev_sup_hs = true; - if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { - is_pltfrm_max_hs = true; - min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, - pltfrm_param->hs_tx_gear); + if (host_params->desired_working_mode == UFS_HS_MODE) { + is_host_max_hs = true; + min_host_gear = min_t(u32, host_params->hs_rx_gear, + host_params->hs_tx_gear); } else { - min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, - pltfrm_param->pwm_tx_gear); + min_host_gear = min_t(u32, host_params->pwm_rx_gear, + host_params->pwm_tx_gear); } /* - * device doesn't support HS but - * pltfrm_param->desired_working_mode is HS, - * thus device and pltfrm_param don't agree + * device doesn't support HS but host_params->desired_working_mode is HS, + * thus device and host_params don't agree */ - if (!is_dev_sup_hs && is_pltfrm_max_hs) { + if (!is_dev_sup_hs && is_host_max_hs) { pr_info("%s: device doesn't support HS\n", __func__); return -ENOTSUPP; - } else if (is_dev_sup_hs && is_pltfrm_max_hs) { + } else if (is_dev_sup_hs && is_host_max_hs) { /* * since device supports HS, it supports FAST_MODE. - * since pltfrm_param->desired_working_mode is also HS + * since host_params->desired_working_mode is also HS * then final decision (FAST/FASTAUTO) is done according * to pltfrm_params as it is the restricting factor */ - agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; + agreed_pwr->pwr_rx = host_params->rx_pwr_hs; agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; } else { /* - * here pltfrm_param->desired_working_mode is PWM. + * here host_params->desired_working_mode is PWM. * it doesn't matter whether device supports HS or PWM, - * in both cases pltfrm_param->desired_working_mode will + * in both cases host_params->desired_working_mode will * determine the mode */ - agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; + agreed_pwr->pwr_rx = host_params->rx_pwr_pwm; agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; } @@ -349,9 +348,9 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, * the same decision will be made for rx */ agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, - pltfrm_param->tx_lanes); + host_params->tx_lanes); agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, - pltfrm_param->rx_lanes); + host_params->rx_lanes); /* device maximum gear is the minimum between device rx and tx gears */ min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); @@ -364,26 +363,26 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, * what is the gear, as it is the one that also decided previously what * pwr the device will be configured to. */ - if ((is_dev_sup_hs && is_pltfrm_max_hs) || - (!is_dev_sup_hs && !is_pltfrm_max_hs)) { + if ((is_dev_sup_hs && is_host_max_hs) || + (!is_dev_sup_hs && !is_host_max_hs)) { agreed_pwr->gear_rx = - min_t(u32, min_dev_gear, min_pltfrm_gear); + min_t(u32, min_dev_gear, min_host_gear); } else if (!is_dev_sup_hs) { agreed_pwr->gear_rx = min_dev_gear; } else { - agreed_pwr->gear_rx = min_pltfrm_gear; + agreed_pwr->gear_rx = min_host_gear; } agreed_pwr->gear_tx = agreed_pwr->gear_rx; - agreed_pwr->hs_rate = pltfrm_param->hs_rate; + agreed_pwr->hs_rate = host_params->hs_rate; return 0; } -EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); +EXPORT_SYMBOL_GPL(ufshcd_negotiate_pwr_params); -void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) +void ufshcd_init_host_params(struct ufs_host_params *host_params) { - *dev_param = (struct ufs_dev_params){ + *host_params = (struct ufs_host_params){ .tx_lanes = UFS_LANE_2, .rx_lanes = UFS_LANE_2, .hs_rx_gear = UFS_HS_G3, @@ -398,7 +397,7 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) .desired_working_mode = UFS_HS_MODE, }; } -EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param); +EXPORT_SYMBOL_GPL(ufshcd_init_host_params); /** * ufshcd_pltfrm_init - probe routine of the driver diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h index a86a3ada4bef..df387be5216b 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.h +++ b/drivers/ufs/host/ufshcd-pltfrm.h @@ -10,7 +10,7 @@ #define UFS_PWM_MODE 1 #define UFS_HS_MODE 2 -struct ufs_dev_params { +struct ufs_host_params { u32 pwm_rx_gear; /* pwm rx gear to work in */ u32 pwm_tx_gear; /* pwm tx gear to work in */ u32 hs_rx_gear; /* hs rx gear to work in */ @@ -25,10 +25,10 @@ struct ufs_dev_params { u32 desired_working_mode; }; -int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *dev_param, - const struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr); -void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param); +int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, + const struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr); +void ufshcd_init_host_params(struct ufs_host_params *host_params); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); int ufshcd_populate_vreg(struct device *dev, const char *name, -- cgit From dc604b4c9d6007c0a03ad90296e849bc38c0d2cc Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:08 -0800 Subject: scsi: ufs: ufs-qcom: No need to set hs_rate after ufshcd_init_host_param() In ufs_qcom_pwr_change_notify(), host_params.hs_rate has been set to PA_HS_MODE_B by ufshcd_init_host_param(), hence remove the duplicated line of work. Meanwhile, removed the macro UFS_QCOM_LIMIT_HS_RATE as it is only used here. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Reviewed-by: Andrew Halaney Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-3-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 1 - drivers/ufs/host/ufs-qcom.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 197c5a5ab136..c21ff2cd7aa6 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -909,7 +909,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: ufshcd_init_host_params(&host_params); - host_params.hs_rate = UFS_QCOM_LIMIT_HS_RATE; /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba); diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 9950a0089475..82cd1436f42d 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -27,8 +27,6 @@ #define SLOW 1 #define FAST 2 -#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B - /* QCOM UFS host controller vendor specific registers */ enum { REG_UFS_SYS1CLK_1US = 0xC0, -- cgit From 55820a7f2cb9b9a4b603cc22dcf0ca5331f86d25 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:09 -0800 Subject: scsi: ufs: ufs-qcom: Setup host power mode during init Setup host power mode and its limitations during UFS host driver init to avoid repetitive work during every power mode change. Acked-by: Andrew Halaney Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Co-developed-by: Bao D. Nguyen Signed-off-by: Bao D. Nguyen Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-4-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 21 ++++++++++++++------- drivers/ufs/host/ufs-qcom.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index c21ff2cd7aa6..9a900196509f 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -898,7 +898,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_host_params host_params; + struct ufs_host_params *host_params = &host->host_params; int ret = 0; if (!dev_req_params) { @@ -908,12 +908,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufshcd_init_host_params(&host_params); - - /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ - host_params.hs_tx_gear = host_params.hs_rx_gear = ufs_qcom_get_hs_gear(hba); - - ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); + ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); @@ -1048,6 +1043,17 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; } +static void ufs_qcom_set_host_params(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_host_params *host_params = &host->host_params; + + ufshcd_init_host_params(host_params); + + /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ + host_params->hs_tx_gear = host_params->hs_rx_gear = ufs_qcom_get_hs_gear(hba); +} + static void ufs_qcom_set_caps(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -1272,6 +1278,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_host_params(hba); err = ufs_qcom_ice_init(host); if (err) diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 82cd1436f42d..11419ebd2082 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -238,6 +238,7 @@ struct ufs_qcom_host { struct gpio_desc *device_reset; + struct ufs_host_params host_params; u32 phy_gear; bool esi_enabled; -- cgit From 743e1f596cccd371e7467fe585a1836773fbd922 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:10 -0800 Subject: scsi: ufs: ufs-qcom: Allow the first init start with the maximum supported gear During host driver init, the phy_gear is set to the minimum supported gear (HS_G2). Then, during the first power mode change, the negotiated gear, say HS-G4, is updated to the phy_gear variable so that in the second init the updated phy_gear can be used to program the PHY. But the current code only allows update the phy_gear to a higher value. If one wants to start the first init with the maximum support gear, say HS-G4, the phy_gear is not updated to HS-G3 if the device only supports HS-G3. The original check added there is intend to make sure the phy_gear won't be updated when gear is scaled down (during clock scaling). Update the check so that one can start the first init with the maximum support gear without breaking the original fix by checking the ufshcd_state, that is, allow update to phy_gear only if power mode change is invoked from ufshcd_probe_hba(). Reviewed-by: Manivannan Sadhasivam Reviewed-by: Nitin Rawat Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-5-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 9a900196509f..81056b9f9c5d 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -916,11 +916,12 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, } /* - * Update phy_gear only when the gears are scaled to a higher value. This is - * because, the PHY gear settings are backwards compatible and we only need to - * change the PHY gear settings while scaling to higher gears. + * During UFS driver probe, always update the PHY gear to match the negotiated + * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled, + * the second init can program the optimal PHY settings. This allows one to start + * the first init with either the minimum or the maximum support gear. */ - if (dev_req_params->gear_tx > host->phy_gear) + if (hba->ufshcd_state == UFSHCD_STATE_RESET) host->phy_gear = dev_req_params->gear_tx; /* enable the device ref clock before changing to HS mode */ -- cgit From 9d8528a833fc0b4f47f7e43481c037390dd9ed71 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:11 -0800 Subject: scsi: ufs: ufs-qcom: Limit HS-G5 Rate-A to hosts with HW version 5 Qcom UFS hosts, with HW ver 5, can only support up to HS-G5 Rate-A due to HW limitations. If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A, so that the subsequent power mode changes shall stick to Rate-A. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-6-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 81056b9f9c5d..aca619986c78 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -442,9 +442,25 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_host_params *host_params = &host->host_params; struct phy *phy = host->generic_phy; + enum phy_mode mode; int ret; + /* + * HW ver 5 can only support up to HS-G5 Rate-A due to HW limitations. + * If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A, + * so that the subsequent power mode change shall stick to Rate-A. + */ + if (host->hw_ver.major == 0x5) { + if (host->phy_gear == UFS_HS_G5) + host_params->hs_rate = PA_HS_MODE_A; + else + host_params->hs_rate = PA_HS_MODE_B; + } + + mode = host_params->hs_rate == PA_HS_MODE_B ? PHY_MODE_UFS_HS_B : PHY_MODE_UFS_HS_A; + /* Reset UFS Host Controller and PHY */ ret = ufs_qcom_host_reset(hba); if (ret) @@ -459,7 +475,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return ret; } - phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear); + phy_set_mode_ext(phy, mode, host->phy_gear); /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); -- cgit From 0bd3cb895d195cdd44da9186bb5b3e0333f1d381 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:12 -0800 Subject: scsi: ufs: ufs-qcom: Set initial PHY gear to max HS gear for HW ver 4 and newer Since HW ver 4, max HS gear can be get from UFS host controller's register, use the max HS gear as the initial PHY gear instead of UFS_HS_G2, so that we don't need to update the hard code for newer targets in future. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-7-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index aca619986c78..543939c4c463 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1060,6 +1060,22 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; } +static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) +{ + struct ufs_host_params *host_params = &host->host_params; + + host->phy_gear = host_params->hs_tx_gear; + + /* + * For controllers whose major HW version is < 4, power up the PHY using + * minimum supported gear (UFS_HS_G2). Switching to max gear will be + * performed during reinit if supported. For newer controllers, whose + * major HW version is >= 4, power up the PHY using max supported gear. + */ + if (host->hw_ver.major < 0x4) + host->phy_gear = UFS_HS_G2; +} + static void ufs_qcom_set_host_params(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -1296,6 +1312,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); ufs_qcom_set_host_params(hba); + ufs_qcom_set_phy_gear(host); err = ufs_qcom_ice_init(host); if (err) @@ -1313,12 +1330,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_warn(dev, "%s: failed to configure the testbus %d\n", __func__, err); - /* - * Power up the PHY using the minimum supported gear (UFS_HS_G2). - * Switching to max gear will be performed during reinit if supported. - */ - host->phy_gear = UFS_HS_G2; - return 0; out_variant_clear: -- cgit From a68abdadfe13fa95a306363fa284b5cf0b79776d Mon Sep 17 00:00:00 2001 From: Can Guo Date: Sat, 2 Dec 2023 04:36:13 -0800 Subject: scsi: ufs: ufs-qcom: Check return value of phy_set_mode_ext() In ufs_qcom_power_up_sequence(), check return value of phy_set_mode_ext() and stop proceeding if phy_set_mode_ext() fails. Reviewed-by: Nitin Rawat Reviewed-by: Manivannan Sadhasivam Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-8-git-send-email-quic_cang@quicinc.com Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 543939c4c463..ee3f07a9e624 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -475,7 +475,9 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return ret; } - phy_set_mode_ext(phy, mode, host->phy_gear); + ret = phy_set_mode_ext(phy, mode, host->phy_gear); + if (ret) + goto out_disable_phy; /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); -- cgit From dc7c948d74e12ed9f40328696b301860243a1ae8 Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Sat, 2 Dec 2023 04:36:14 -0800 Subject: scsi: ufs: ufs-qcom: Add support for UFS device version detection Start from HW ver 5, a spare register in UFS host controller is added and used to indicate the UFS device version. The spare register is populated by bootloader for now, but in future it will be populated by HW automatically during link startup with its best efforts in any boot stage prior to Linux. During host driver init, read the spare register, if it is not populated with a UFS device version, go ahead with the dual init mechanism. If a UFS device version is in there, use the UFS device version together with host controller's HW version to decide the proper PHY gear which should be used to configure the UFS PHY without going through the second init. Signed-off-by: Bao D. Nguyen Signed-off-by: Can Guo Link: https://lore.kernel.org/r/1701520577-31163-9-git-send-email-quic_cang@quicinc.com Reviewed-by: Manivannan Sadhasivam Reviewed-by: Nitin Rawat Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 35 ++++++++++++++++++++++++++++------- drivers/ufs/host/ufs-qcom.h | 4 ++++ 2 files changed, 32 insertions(+), 7 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index ee3f07a9e624..968a4c00b5ec 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1065,17 +1065,38 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) { struct ufs_host_params *host_params = &host->host_params; + u32 val, dev_major; host->phy_gear = host_params->hs_tx_gear; - /* - * For controllers whose major HW version is < 4, power up the PHY using - * minimum supported gear (UFS_HS_G2). Switching to max gear will be - * performed during reinit if supported. For newer controllers, whose - * major HW version is >= 4, power up the PHY using max supported gear. - */ - if (host->hw_ver.major < 0x4) + if (host->hw_ver.major < 0x4) { + /* + * For controllers whose major HW version is < 4, power up the + * PHY using minimum supported gear (UFS_HS_G2). Switching to + * max gear will be performed during reinit if supported. + * For newer controllers, whose major HW version is >= 4, power + * up the PHY using max supported gear. + */ host->phy_gear = UFS_HS_G2; + } else if (host->hw_ver.major >= 0x5) { + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG); + dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, val); + + /* + * Since the UFS device version is populated, let's remove the + * REINIT quirk as the negotiated gear won't change during boot. + * So there is no need to do reinit. + */ + if (dev_major != 0x0) + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + + /* + * For UFS 3.1 device and older, power up the PHY using HS-G4 + * PHY gear to save power. + */ + if (dev_major > 0x0 && dev_major < 0x4) + host->phy_gear = UFS_HS_G4; + } } static void ufs_qcom_set_host_params(struct ufs_hba *hba) diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 11419ebd2082..32e51d90e8e7 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -23,6 +23,8 @@ #define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) #define UFS_HW_VER_STEP_MASK GENMASK(15, 0) +#define UFS_DEV_VER_MAJOR_MASK GENMASK(7, 4) + /* vendor specific pre-defined parameters */ #define SLOW 1 #define FAST 2 @@ -54,6 +56,8 @@ enum { UFS_AH8_CFG = 0xFC, REG_UFS_CFG3 = 0x271C, + + REG_UFS_DEBUG_SPARE_CFG = 0x284C, }; /* QCOM UFS host controller vendor specific debug registers */ -- cgit From 9caef8568831c3e4bff77036d1515c7abb79eb92 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:46 +0530 Subject: scsi: ufs: qcom: Use clk_bulk APIs for managing lane clocks Lane clock handling can be simplified by using the clk_bulk APIs. So let's make use of them. This also get's rid of the clock validation in the driver as kernel should just rely on the firmware (DT/ACPI) to provide the clocks required for proper functioning. Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-2-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 94 +++------------------------------------------ drivers/ufs/host/ufs-qcom.h | 6 +-- 2 files changed, 7 insertions(+), 93 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 96cb8b5b4e66..cbb6a696cd97 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -194,52 +194,12 @@ static inline int ufs_qcom_ice_suspend(struct ufs_qcom_host *host) } #endif -static int ufs_qcom_host_clk_get(struct device *dev, - const char *name, struct clk **clk_out, bool optional) -{ - struct clk *clk; - int err = 0; - - clk = devm_clk_get(dev, name); - if (!IS_ERR(clk)) { - *clk_out = clk; - return 0; - } - - err = PTR_ERR(clk); - - if (optional && err == -ENOENT) { - *clk_out = NULL; - return 0; - } - - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to get %s err %d\n", name, err); - - return err; -} - -static int ufs_qcom_host_clk_enable(struct device *dev, - const char *name, struct clk *clk) -{ - int err = 0; - - err = clk_prepare_enable(clk); - if (err) - dev_err(dev, "%s: %s enable failed %d\n", __func__, name, err); - - return err; -} - static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) { if (!host->is_lane_clks_enabled) return; - clk_disable_unprepare(host->tx_l1_sync_clk); - clk_disable_unprepare(host->tx_l0_sync_clk); - clk_disable_unprepare(host->rx_l1_sync_clk); - clk_disable_unprepare(host->rx_l0_sync_clk); + clk_bulk_disable_unprepare(host->num_clks, host->clks); host->is_lane_clks_enabled = false; } @@ -247,43 +207,14 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) { int err; - struct device *dev = host->hba->dev; - - if (host->is_lane_clks_enabled) - return 0; - err = ufs_qcom_host_clk_enable(dev, "rx_lane0_sync_clk", - host->rx_l0_sync_clk); + err = clk_bulk_prepare_enable(host->num_clks, host->clks); if (err) return err; - err = ufs_qcom_host_clk_enable(dev, "tx_lane0_sync_clk", - host->tx_l0_sync_clk); - if (err) - goto disable_rx_l0; - - err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk", - host->rx_l1_sync_clk); - if (err) - goto disable_tx_l0; - - err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", - host->tx_l1_sync_clk); - if (err) - goto disable_rx_l1; - host->is_lane_clks_enabled = true; return 0; - -disable_rx_l1: - clk_disable_unprepare(host->rx_l1_sync_clk); -disable_tx_l0: - clk_disable_unprepare(host->tx_l0_sync_clk); -disable_rx_l0: - clk_disable_unprepare(host->rx_l0_sync_clk); - - return err; } static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) @@ -294,26 +225,11 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) if (has_acpi_companion(dev)) return 0; - err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk", - &host->rx_l0_sync_clk, false); - if (err) - return err; - - err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk", - &host->tx_l0_sync_clk, false); - if (err) + err = devm_clk_bulk_get_all(dev, &host->clks); + if (err <= 0) return err; - /* In case of single lane per direction, don't read lane1 clocks */ - if (host->hba->lanes_per_direction > 1) { - err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk", - &host->rx_l1_sync_clk, false); - if (err) - return err; - - err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", - &host->tx_l1_sync_clk, true); - } + host->num_clks = err; return 0; } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 9950a0089475..e2df4c528a2a 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -213,10 +213,8 @@ struct ufs_qcom_host { struct phy *generic_phy; struct ufs_hba *hba; struct ufs_pa_layer_attr dev_req_params; - struct clk *rx_l0_sync_clk; - struct clk *tx_l0_sync_clk; - struct clk *rx_l1_sync_clk; - struct clk *tx_l1_sync_clk; + struct clk_bulk_data *clks; + u32 num_clks; bool is_lane_clks_enabled; struct icc_path *icc_ddr; -- cgit From 3bf7ab4ac30c03beecf57c052e87d5a38fb8aed6 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:47 +0530 Subject: scsi: ufs: qcom: Fix the return value of ufs_qcom_ice_program_key() Currently, the function returns -EINVAL if algorithm other than AES-256-XTS is requested. But the correct error code is -EOPNOTSUPP. Fix it! Cc: Abel Vesa Fixes: 56541c7c4468 ("scsi: ufs: ufs-qcom: Switch to the new ICE API") Reviewed-by: Abel Vesa Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-3-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index cbb6a696cd97..852179e456f2 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -158,7 +158,7 @@ static int ufs_qcom_ice_program_key(struct ufs_hba *hba, cap = hba->crypto_cap_array[cfg->crypto_cap_idx]; if (cap.algorithm_id != UFS_CRYPTO_ALG_AES_XTS || cap.key_size != UFS_CRYPTO_KEY_SIZE_256) - return -EINVAL; + return -EOPNOTSUPP; if (config_enable) return qcom_ice_program_key(host->ice, -- cgit From 3a747c5cf9b6c36649783b28d2ef8f9c92b16a0f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:48 +0530 Subject: scsi: ufs: qcom: Fix the return value when platform_get_resource_byname() fails The return value should be -ENODEV indicating that the resource is not provided in DT, not -ENOMEM. Fix it! Fixes: c263b4ef737e ("scsi: ufs: core: mcq: Configure resource regions") Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-4-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 852179e456f2..778df0a9c65e 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1701,7 +1701,7 @@ static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba) if (!res->resource) { dev_info(hba->dev, "Resource %s not provided\n", res->name); if (i == RES_UFS) - return -ENOMEM; + return -ENODEV; continue; } else if (i == RES_UFS) { res_mem = res->resource; -- cgit From 1f165c87ec3ec9bd87860f2adef3f1333106f082 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:49 +0530 Subject: scsi: ufs: qcom: Remove superfluous variable assignments There are many instances where the variable assignments are not needed. Remove them. Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-5-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 778df0a9c65e..dc93b1c5ca74 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -219,7 +219,7 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) { - int err = 0; + int err; struct device *dev = host->hba->dev; if (has_acpi_companion(dev)) @@ -237,7 +237,7 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) static int ufs_qcom_check_hibern8(struct ufs_hba *hba) { int err; - u32 tx_fsm_val = 0; + u32 tx_fsm_val; unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS); do { @@ -292,9 +292,9 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) */ static int ufs_qcom_host_reset(struct ufs_hba *hba) { - int ret = 0; + int ret; struct ufs_qcom_host *host = ufshcd_get_variant(hba); - bool reenable_intr = false; + bool reenable_intr; if (!host->core_reset) { dev_warn(hba->dev, "%s: reset control not set\n", __func__); @@ -417,7 +417,7 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; + int err; switch (status) { case PRE_CHANGE: @@ -463,7 +463,7 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 core_clk_period_in_ns; u32 tx_clk_cycles_per_us = 0; unsigned long core_clk_rate = 0; - u32 core_clk_cycles_per_us = 0; + u32 core_clk_cycles_per_us; static u32 pwm_fr_table[][2] = { {UFS_PWM_G1, 0x1}, @@ -1418,7 +1418,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; + int err; /* check the host controller state before sending hibern8 cmd */ if (!ufshcd_is_hba_active(hba)) @@ -1689,7 +1689,7 @@ static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba) struct platform_device *pdev = to_platform_device(hba->dev); struct ufshcd_res_info *res; struct resource *res_mem, *res_mcq; - int i, ret = 0; + int i, ret; memcpy(hba->res, ufs_res_info, sizeof(ufs_res_info)); -- cgit From d42d368647dac42e8e91c10daf3f8261d7996380 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:50 +0530 Subject: scsi: ufs: qcom: Remove the warning message when core_reset is not available core_reset is optional, so there is no need to warn the user if it is not available. Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-6-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index dc93b1c5ca74..d474de0739e4 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -296,10 +296,8 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba) struct ufs_qcom_host *host = ufshcd_get_variant(hba); bool reenable_intr; - if (!host->core_reset) { - dev_warn(hba->dev, "%s: reset control not set\n", __func__); + if (!host->core_reset) return 0; - } reenable_intr = hba->is_irq_enabled; disable_irq(hba->irq); -- cgit From 0ae7a02726bca95ee9d17de0ccfcd1de0ff4e429 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:51 +0530 Subject: scsi: ufs: qcom: Export ufshcd_{enable/disable}_irq helpers and make use of them Instead of duplicating the enable/disable IRQ part, let's export the helpers available in ufshcd driver and make use of them. This also fixes the possible redundant IRQ disable before asserting reset (when IRQ was already disabled). Fixes: 4a791574a0cc ("scsi: ufs: ufs-qcom: Disable interrupt in reset path") Reviewed-by: Bart Van Assche Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-7-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 6 ++++-- drivers/ufs/host/ufs-qcom.c | 9 +++------ 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 8b1031fb0a44..671facc73921 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -289,21 +289,23 @@ static void ufshcd_wb_toggle_buf_flush_during_h8(struct ufs_hba *hba, static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba); static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba); -static inline void ufshcd_enable_irq(struct ufs_hba *hba) +void ufshcd_enable_irq(struct ufs_hba *hba) { if (!hba->is_irq_enabled) { enable_irq(hba->irq); hba->is_irq_enabled = true; } } +EXPORT_SYMBOL_GPL(ufshcd_enable_irq); -static inline void ufshcd_disable_irq(struct ufs_hba *hba) +void ufshcd_disable_irq(struct ufs_hba *hba) { if (hba->is_irq_enabled) { disable_irq(hba->irq); hba->is_irq_enabled = false; } } +EXPORT_SYMBOL_GPL(ufshcd_disable_irq); static void ufshcd_configure_wb(struct ufs_hba *hba) { diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index d474de0739e4..604273a22afd 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -300,8 +300,7 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba) return 0; reenable_intr = hba->is_irq_enabled; - disable_irq(hba->irq); - hba->is_irq_enabled = false; + ufshcd_disable_irq(hba); ret = reset_control_assert(host->core_reset); if (ret) { @@ -324,10 +323,8 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba) usleep_range(1000, 1100); - if (reenable_intr) { - enable_irq(hba->irq); - hba->is_irq_enabled = true; - } + if (reenable_intr) + ufshcd_enable_irq(hba); return 0; } -- cgit From d11954711499f02fb57d1f6a7022f13b5380c046 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:52 +0530 Subject: scsi: ufs: qcom: Fail ufs_qcom_power_up_sequence() when core_reset fails Even though core_reset is optional, a failure during assert/deassert should be considered fatal, if core_reset is available. So fail ufs_qcom_power_up_sequence() if an error happens during reset and also get rid of the redundant warning as the ufs_qcom_host_reset() function itself prints error messages. Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-8-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 604273a22afd..365a61dbf7ea 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -317,9 +317,11 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba) usleep_range(200, 210); ret = reset_control_deassert(host->core_reset); - if (ret) + if (ret) { dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n", __func__, ret); + return ret; + } usleep_range(1000, 1100); @@ -359,8 +361,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) /* Reset UFS Host Controller and PHY */ ret = ufs_qcom_host_reset(hba); if (ret) - dev_warn(hba->dev, "%s: host reset returned %d\n", - __func__, ret); + return ret; /* phy initialization - calibrate the phy */ ret = phy_init(phy); -- cgit From e430c0e08957d111b068d5c0a3f4ddd1b8d790cb Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:53 +0530 Subject: scsi: ufs: qcom: Check the return value of ufs_qcom_power_up_sequence() If ufs_qcom_power_up_sequence() fails, then it makes no sense to enable the lane clocks and continue ufshcd_hba_enable(). So let's check the return value of ufs_qcom_power_up_sequence(). Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-9-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 365a61dbf7ea..b141dd2a9346 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -417,7 +417,10 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufs_qcom_power_up_sequence(hba); + err = ufs_qcom_power_up_sequence(hba); + if (err) + return err; + /* * The PHY PLL output is the source of tx/rx lane symbol * clocks, hence, enable the lane clocks only after PHY -- cgit From 8291652ed8a20b7c19a6fce0ad04cccbd629a620 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:54 +0530 Subject: scsi: ufs: qcom: Remove redundant error print for devm_kzalloc() failure devm_kzalloc() will itself print the error message on failure. So let's get rid of the redundant error message in ufs_qcom_init(). Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-10-manivannan.sadhasivam@linaro.org Reviewed-by: Nitin Rawat Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index b141dd2a9346..05a9a25bc34c 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1109,10 +1109,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) struct ufs_clk_info *clki; host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(dev, "%s: no memory for qcom ufs host\n", __func__); + if (!host) return -ENOMEM; - } /* Make a two way bind between the qcom host and the hba */ host->hba = hba; -- cgit From c7afadacc180ae655aa98577aca8fb5fdfb4a761 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:55 +0530 Subject: scsi: ufs: qcom: Use dev_err_probe() to simplify error handling of devm_gpiod_get_optional() As done in other places, let's use dev_err_probe() to simplify the error handling while acquiring the device reset gpio using devm_gpiod_get_optional(). While at it, let's reword the error message to make it clear that the failure is due to acquiring "device reset gpio". Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-11-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 05a9a25bc34c..ae9fafa49ded 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1148,9 +1148,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) host->device_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(host->device_reset)) { - err = PTR_ERR(host->device_reset); - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to acquire reset gpio: %d\n", err); + err = dev_err_probe(dev, PTR_ERR(host->device_reset), + "Failed to acquire device reset gpio\n"); goto out_variant_clear; } -- cgit From e7458beab8094bc9b0e1feecaa2c7bef1718aa2f Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:56 +0530 Subject: scsi: ufs: qcom: Remove unused ufs_qcom_hosts struct array ufs_qcom_hosts array is assigned, but not used anywhere. So let's remove it. Reviewed-by: Andrew Halaney Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-12-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 5 ----- drivers/ufs/host/ufs-qcom.h | 1 - 2 files changed, 6 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index ae9fafa49ded..18ea41f5bae9 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -90,8 +90,6 @@ static const struct __ufs_qcom_bw_table { [MODE_MAX][0][0] = { 7643136, 307200 }, }; -static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; - static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up); @@ -1194,9 +1192,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_setup_clocks(hba, true, POST_CHANGE); - if (hba->dev->id < MAX_UFS_QCOM_HOSTS) - ufs_qcom_hosts[hba->dev->id] = host; - ufs_qcom_get_default_testbus_cfg(host); err = ufs_qcom_testbus_config(host); if (err) diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index e2df4c528a2a..53db424a0bcb 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -10,7 +10,6 @@ #include #include -#define MAX_UFS_QCOM_HOSTS 1 #define MAX_U32 (~(u32)0) #define MPHY_TX_FSM_STATE 0x41 #define TX_FSM_HIBERN8 0x1 -- cgit From be2e06c81a31cf4cf388d80af5ebc9bdc7a8430e Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:57 +0530 Subject: scsi: ufs: qcom: Sort includes alphabetically Sort includes alphabetically. Reviewed-by: Nitin Rawat Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-13-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 18ea41f5bae9..7fbd35a3eb81 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -4,26 +4,26 @@ */ #include -#include #include #include +#include +#include #include #include #include -#include #include -#include +#include #include -#include +#include #include #include -#include "ufshcd-pltfrm.h" -#include -#include "ufs-qcom.h" #include #include +#include +#include "ufshcd-pltfrm.h" +#include "ufs-qcom.h" #define MCQ_QCFGPTR_MASK GENMASK(7, 0) #define MCQ_QCFGPTR_UNIT 0x200 -- cgit From 3b60f4564ff5b0e33d0d256b17594e223f0bcac8 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:58 +0530 Subject: scsi: ufs: qcom: Initialize cycles_in_1us variable in ufs_qcom_set_core_clk_ctrl() In case the "core_clk_unipro" clock is not provided, "cycles_in_1us" variable will be used as uninitialized. So initialize it with 0. Issue reported by Smatch tool: drivers/ufs/host/ufs-qcom.c:1336 ufs_qcom_set_core_clk_ctrl() error: uninitialized symbol 'cycles_in_1us'. drivers/ufs/host/ufs-qcom.c:1341 ufs_qcom_set_core_clk_ctrl() error: uninitialized symbol 'cycles_in_1us'. Reviewed-by: Nitin Rawat Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-14-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 7fbd35a3eb81..9b3d6d3609c9 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1298,7 +1298,7 @@ static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct list_head *head = &hba->clk_list_head; struct ufs_clk_info *clki; - u32 cycles_in_1us; + u32 cycles_in_1us = 0; u32 core_clk_ctrl_reg; int err; -- cgit From 6b481af25ec0edaff8d7b39b2fa17e2f645afc8d Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:28:59 +0530 Subject: scsi: ufs: qcom: Simplify ufs_qcom_{assert/deassert}_reset In both the functions, UFS_PHY_SOFT_RESET contains the mask of the reset bit. So this can be passed directly as the value to be written for asserting the reset. For deasserting, 0 can be passed. This gets rid of the FIELD_PREP() inside these functions and also UFS_PHY_RESET_{ENABLE/DISABLE} definitions. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-15-manivannan.sadhasivam@linaro.org Reviewed-by: Andrew Halaney Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 53db424a0bcb..a109d3359db4 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -92,9 +92,6 @@ enum { #define TEST_BUS_SEL GENMASK(22, 19) #define UFS_REG_TEST_BUS_EN BIT(30) -#define UFS_PHY_RESET_ENABLE 1 -#define UFS_PHY_RESET_DISABLE 0 - /* bit definitions for REG_UFS_CFG2 register */ #define UAWM_HW_CGC_EN BIT(0) #define UARM_HW_CGC_EN BIT(1) @@ -157,8 +154,7 @@ ufs_qcom_get_controller_revision(struct ufs_hba *hba, static inline void ufs_qcom_assert_reset(struct ufs_hba *hba) { - ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_ENABLE), - REG_UFS_CFG1); + ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, UFS_PHY_SOFT_RESET, REG_UFS_CFG1); /* * Make sure assertion of ufs phy reset is written to @@ -169,8 +165,7 @@ static inline void ufs_qcom_assert_reset(struct ufs_hba *hba) static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba) { - ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_DISABLE), - REG_UFS_CFG1); + ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, 0, REG_UFS_CFG1); /* * Make sure de-assertion of ufs phy reset is written to -- cgit From 104cd58d9af80f03993607ac86bcd88c10cfba3d Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:29:00 +0530 Subject: scsi: ufs: qcom: Remove support for host controllers older than v2.0 The legacy platforms making use of host controllers older than version 2.0 are not supported in upstream. So there is no need to carry code to support them. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-16-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 196 +++----------------------------------------- drivers/ufs/host/ufs-qcom.h | 27 ------ 2 files changed, 11 insertions(+), 212 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 9b3d6d3609c9..26aa8904c823 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -274,9 +274,7 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) { - ufshcd_rmwl(host->hba, QUNIPRO_SEL, - ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0, - REG_UFS_CFG1); + ufshcd_rmwl(host->hba, QUNIPRO_SEL, QUNIPRO_SEL, REG_UFS_CFG1); if (host->hw_ver.major >= 0x05) ufshcd_rmwl(host->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0); @@ -333,18 +331,8 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (host->hw_ver.major == 0x1) { - /* - * HS-G3 operations may not reliably work on legacy QCOM - * UFS host controller hardware even though capability - * exchange during link startup phase may end up - * negotiating maximum supported gear as G3. - * Hence downgrade the maximum supported gear to HS-G2. - */ - return UFS_HS_G2; - } else if (host->hw_ver.major >= 0x4) { + if (host->hw_ver.major >= 0x4) return UFS_QCOM_MAX_GEAR(ufshcd_readl(hba, REG_UFS_PARAM0)); - } /* Default is HS-G3 */ return UFS_HS_G3; @@ -457,41 +445,16 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, { struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_clk_info *clki; - u32 core_clk_period_in_ns; - u32 tx_clk_cycles_per_us = 0; unsigned long core_clk_rate = 0; u32 core_clk_cycles_per_us; - static u32 pwm_fr_table[][2] = { - {UFS_PWM_G1, 0x1}, - {UFS_PWM_G2, 0x1}, - {UFS_PWM_G3, 0x1}, - {UFS_PWM_G4, 0x1}, - }; - - static u32 hs_fr_table_rA[][2] = { - {UFS_HS_G1, 0x1F}, - {UFS_HS_G2, 0x3e}, - {UFS_HS_G3, 0x7D}, - }; - - static u32 hs_fr_table_rB[][2] = { - {UFS_HS_G1, 0x24}, - {UFS_HS_G2, 0x49}, - {UFS_HS_G3, 0x92}, - }; - /* - * The Qunipro controller does not use following registers: - * SYS1CLK_1US_REG, TX_SYMBOL_CLK_1US_REG, CLK_NS_REG & - * UFS_REG_PA_LINK_STARTUP_TIMER. - * However UTP controller uses SYS1CLK_1US_REG register for Interrupt + * UTP controller uses SYS1CLK_1US_REG register for Interrupt * Aggregation logic. * It is mandatory to write SYS1CLK_1US_REG register on UFS host * controller V4.0.0 onwards. */ - if (host->hw_ver.major < 4 && ufs_qcom_cap_qunipro(host) && - !ufshcd_is_intr_aggr_allowed(hba)) + if (host->hw_ver.major < 4 && !ufshcd_is_intr_aggr_allowed(hba)) return 0; if (gear == 0) { @@ -524,79 +487,6 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, mb(); } - if (ufs_qcom_cap_qunipro(host)) - return 0; - - core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; - core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; - core_clk_period_in_ns &= MASK_CLK_NS_REG; - - switch (hs) { - case FASTAUTO_MODE: - case FAST_MODE: - if (rate == PA_HS_MODE_A) { - if (gear > ARRAY_SIZE(hs_fr_table_rA)) { - dev_err(hba->dev, - "%s: index %d exceeds table size %zu\n", - __func__, gear, - ARRAY_SIZE(hs_fr_table_rA)); - return -EINVAL; - } - tx_clk_cycles_per_us = hs_fr_table_rA[gear-1][1]; - } else if (rate == PA_HS_MODE_B) { - if (gear > ARRAY_SIZE(hs_fr_table_rB)) { - dev_err(hba->dev, - "%s: index %d exceeds table size %zu\n", - __func__, gear, - ARRAY_SIZE(hs_fr_table_rB)); - return -EINVAL; - } - tx_clk_cycles_per_us = hs_fr_table_rB[gear-1][1]; - } else { - dev_err(hba->dev, "%s: invalid rate = %d\n", - __func__, rate); - return -EINVAL; - } - break; - case SLOWAUTO_MODE: - case SLOW_MODE: - if (gear > ARRAY_SIZE(pwm_fr_table)) { - dev_err(hba->dev, - "%s: index %d exceeds table size %zu\n", - __func__, gear, - ARRAY_SIZE(pwm_fr_table)); - return -EINVAL; - } - tx_clk_cycles_per_us = pwm_fr_table[gear-1][1]; - break; - case UNCHANGED: - default: - dev_err(hba->dev, "%s: invalid mode = %d\n", __func__, hs); - return -EINVAL; - } - - if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) != - (core_clk_period_in_ns | tx_clk_cycles_per_us)) { - /* this register 2 fields shall be written at once */ - ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, - REG_UFS_TX_SYMBOL_CLK_NS_US); - /* - * make sure above write gets applied before we return from - * this function. - */ - mb(); - } - - if (update_link_startup_timer && host->hw_ver.major != 0x5) { - ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100), - REG_UFS_CFG0); - /* - * make sure that this configuration is applied before - * we return - */ - mb(); - } - return 0; } @@ -604,7 +494,6 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { int err = 0; - struct ufs_qcom_host *host = ufshcd_get_variant(hba); switch (status) { case PRE_CHANGE: @@ -615,11 +504,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, return -EINVAL; } - if (ufs_qcom_cap_qunipro(host)) { - err = ufs_qcom_set_core_clk_ctrl(hba, true); - if (err) - dev_err(hba->dev, "cfg core clk ctrl failed\n"); - } + err = ufs_qcom_set_core_clk_ctrl(hba, true); + if (err) + dev_err(hba->dev, "cfg core clk ctrl failed\n"); /* * Some UFS devices (and may be host) have issues if LCC is * enabled. So we are setting PA_Local_TX_LCC_Enable to 0 @@ -918,12 +805,7 @@ static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - - if (host->hw_ver.major == 0x1) - return ufshci_version(1, 1); - else - return ufshci_version(2, 0); + return ufshci_version(2, 0); } /** @@ -939,46 +821,21 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (host->hw_ver.major == 0x01) { - hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS - | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP - | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE; - - if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001) - hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; - - hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; - } - - if (host->hw_ver.major == 0x2) { + if (host->hw_ver.major == 0x2) hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; - if (!ufs_qcom_cap_qunipro(host)) - /* Legacy UniPro mode still need following quirks */ - hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS - | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE - | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP); - } - if (host->hw_ver.major > 0x3) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; } static void ufs_qcom_set_caps(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; hba->caps |= UFSHCD_CAP_CLK_SCALING | UFSHCD_CAP_WB_WITH_CLK_SCALING; hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; hba->caps |= UFSHCD_CAP_WB_EN; hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE; hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND; - - if (host->hw_ver.major >= 0x2) { - host->caps = UFS_QCOM_CAP_QUNIPRO | - UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE; - } } /** @@ -1101,9 +958,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) { int err; struct device *dev = hba->dev; - struct platform_device *pdev = to_platform_device(dev); struct ufs_qcom_host *host; - struct resource *res; struct ufs_clk_info *clki; host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); @@ -1154,25 +1009,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, &host->hw_ver.minor, &host->hw_ver.step); - /* - * for newer controllers, device reference clock control bit has - * moved inside UFS controller register address space itself. - */ - if (host->hw_ver.major >= 0x02) { - host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; - host->dev_ref_clk_en_mask = BIT(26); - } else { - /* "dev_ref_clk_ctrl_mem" is optional resource */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "dev_ref_clk_ctrl_mem"); - if (res) { - host->dev_ref_clk_ctrl_mmio = - devm_ioremap_resource(dev, res); - if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) - host->dev_ref_clk_ctrl_mmio = NULL; - host->dev_ref_clk_en_mask = BIT(5); - } - } + host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; + host->dev_ref_clk_en_mask = BIT(26); list_for_each_entry(clki, &hba->clk_list_head, list) { if (!strcmp(clki->name, "core_clk_unipro")) @@ -1351,9 +1189,6 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) struct ufs_pa_layer_attr *attr = &host->dev_req_params; int ret; - if (!ufs_qcom_cap_qunipro(host)) - return 0; - ret = ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, attr->hs_rate, false, true); if (ret) { @@ -1371,13 +1206,9 @@ static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err; u32 core_clk_ctrl_reg; - if (!ufs_qcom_cap_qunipro(host)) - return 0; - err = ufshcd_dme_get(hba, UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), &core_clk_ctrl_reg); @@ -1396,11 +1227,6 @@ static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - - if (!ufs_qcom_cap_qunipro(host)) - return 0; - /* set unipro core clock attributes and clear clock divider */ return ufs_qcom_set_core_clk_ctrl(hba, false); } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index a109d3359db4..385480499e71 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -114,13 +114,6 @@ enum { DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN) -/* bit offset */ -#define OFFSET_CLK_NS_REG 0xa - -/* bit masks */ -#define MASK_TX_SYMBOL_CLK_1US_REG GENMASK(9, 0) -#define MASK_CLK_NS_REG GENMASK(23, 10) - /* QUniPro Vendor specific attributes */ #define PA_VS_CONFIG_REG1 0x9000 #define DME_VS_CORE_CLK_CTRL 0xD002 @@ -189,21 +182,6 @@ struct ufs_qcom_testbus { struct gpio_desc; struct ufs_qcom_host { - /* - * Set this capability if host controller supports the QUniPro mode - * and if driver wants the Host controller to operate in QUniPro mode. - * Note: By default this capability will be kept enabled if host - * controller supports the QUniPro mode. - */ - #define UFS_QCOM_CAP_QUNIPRO 0x1 - - /* - * Set this capability if host controller can retain the secure - * configuration even after UFS controller core power collapse. - */ - #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE 0x2 - u32 caps; - struct phy *generic_phy; struct ufs_hba *hba; struct ufs_pa_layer_attr dev_req_params; @@ -253,9 +231,4 @@ ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg) int ufs_qcom_testbus_config(struct ufs_qcom_host *host); -static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host) -{ - return host->caps & UFS_QCOM_CAP_QUNIPRO; -} - #endif /* UFS_QCOM_H_ */ -- cgit From 0e9f4375db1ce3fa231d8c7b27dbec9341a2e3ef Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:29:01 +0530 Subject: scsi: ufs: qcom: Use ufshcd_rmwl() where applicable Instead of using both ufshcd_readl() and ufshcd_writel() to read/modify/ write a register, let's make use of the existing helper. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-17-manivannan.sadhasivam@linaro.org Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 12 ++++-------- drivers/ufs/host/ufs-qcom.h | 3 +++ 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 26aa8904c823..549a08645391 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -387,9 +387,8 @@ out_disable_phy: */ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) { - ufshcd_writel(hba, - ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL, - REG_UFS_CFG2); + ufshcd_rmwl(hba, REG_UFS_CFG2_CGC_EN_ALL, REG_UFS_CFG2_CGC_EN_ALL, + REG_UFS_CFG2); /* Ensure that HW clock gating is enabled before next operations */ mb(); @@ -1689,11 +1688,8 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) platform_msi_domain_free_irqs(hba->dev); } else { if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 && - host->hw_ver.step == 0) { - ufshcd_writel(hba, - ufshcd_readl(hba, REG_UFS_CFG3) | 0x1F000, - REG_UFS_CFG3); - } + host->hw_ver.step == 0) + ufshcd_rmwl(hba, ESI_VEC_MASK, 0x1f00, REG_UFS_CFG3); ufshcd_mcq_enable_esi(hba); } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 385480499e71..2ce63a1c7f2f 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -102,6 +102,9 @@ enum { #define TMRLUT_HW_CGC_EN BIT(6) #define OCSC_HW_CGC_EN BIT(7) +/* bit definitions for REG_UFS_CFG3 register */ +#define ESI_VEC_MASK GENMASK(22, 12) + /* bit definitions for REG_UFS_PARAM0 */ #define MAX_HS_GEAR_MASK GENMASK(6, 4) #define UFS_QCOM_MAX_GEAR(x) FIELD_GET(MAX_HS_GEAR_MASK, (x)) -- cgit From cac50d04fffe2ac546a406ea8f5759e0741b2c16 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 8 Dec 2023 12:29:02 +0530 Subject: scsi: ufs: qcom: Remove unused definitions Remove unused definitions. Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231208065902.11006-18-manivannan.sadhasivam@linaro.org Reviewed-by: Andrew Halaney Tested-by: Andrew Halaney # sa8775p-ride Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 2ce63a1c7f2f..cdceeb795e70 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -10,22 +10,16 @@ #include #include -#define MAX_U32 (~(u32)0) #define MPHY_TX_FSM_STATE 0x41 #define TX_FSM_HIBERN8 0x1 #define HBRN8_POLL_TOUT_MS 100 #define DEFAULT_CLK_RATE_HZ 1000000 -#define BUS_VECTOR_NAME_LEN 32 #define MAX_SUPP_MAC 64 #define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28) #define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) #define UFS_HW_VER_STEP_MASK GENMASK(15, 0) -/* vendor specific pre-defined parameters */ -#define SLOW 1 -#define FAST 2 - #define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B /* QCOM UFS host controller vendor specific registers */ -- cgit From 9fa268875ca4ff5cad0c1b957388a0aef39920c3 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 12 Dec 2023 23:08:23 +0100 Subject: scsi: ufs: core: Add ufshcd_is_ufs_dev_busy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper inline for retrieving whether UFS device is busy or not. Signed-off-by: Bean Huo Link: https://lore.kernel.org/r/20231212220825.85255-2-beanhuo@iokpp.de Reviewed-by: Avri Altman Reviewed-by: Thomas Weißschuh Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 8b1031fb0a44..fbe76a872530 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -235,6 +235,12 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state, return UFS_PM_LVL_0; } +static bool ufshcd_is_ufs_dev_busy(struct ufs_hba *hba) +{ + return (hba->clk_gating.active_reqs || hba->outstanding_reqs || hba->outstanding_tasks || + hba->active_uic_cmd || hba->uic_async_done); +} + static const struct ufs_dev_quirk ufs_fixups[] = { /* UFS cards deviations table */ { .wmanufacturerid = UFS_VENDOR_MICRON, @@ -1917,10 +1923,7 @@ static void ufshcd_gate_work(struct work_struct *work) goto rel_lock; } - if (hba->clk_gating.active_reqs - || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL - || hba->outstanding_reqs || hba->outstanding_tasks - || hba->active_uic_cmd || hba->uic_async_done) + if (ufshcd_is_ufs_dev_busy(hba) || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) goto rel_lock; spin_unlock_irqrestore(hba->host->host_lock, flags); -- cgit From 6bf999e0eb41850d5c857102535d5c53b2ede224 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 12 Dec 2023 23:08:24 +0100 Subject: scsi: ufs: core: Add UFS RTC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Real Time Clock (RTC) support for UFS device. This enhancement is crucial for the internal maintenance operations of the UFS device. The patch enables the device to handle both absolute and relative time information. Furthermore, it includes periodic task to update the RTC in accordance with the UFS Spec, ensuring the accuracy of RTC information for the device's internal processes. RTC and qTimestamp serve distinct purposes. The RTC provides a coarse level of granularity with, at best, approximate single-second resolution. This makes the RTC well-suited for the device to determine the approximate age of programmed blocks after being updated by the host. On the other hand, qTimestamp offers nanosecond granularity and is specifically designed for synchronizing Device Error Log entries with corresponding host-side logs. Given that the RTC has been a standard feature since UFS Spec 2.0, and qTimestamp was introduced in UFS Spec 4.0, the majority of UFS devices currently on the market rely on RTC. Therefore, it is advisable to continue supporting RTC in the Linux kernel. This ensures compatibility with the prevailing UFS device implementations and facilitates seamless integration with existing hardware. By maintaining support for RTC, we ensure broad compatibility and avoid potential issues arising from deviations in device specifications across different UFS versions. Signed-off-by: Bean Huo Signed-off-by: Mike Bi Signed-off-by: Luca Porzio Link: https://lore.kernel.org/r/20231212220825.85255-3-beanhuo@iokpp.de Acked-by: Avri Altman Reviewed-by: Thomas Weißschuh Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 83 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index fbe76a872530..99ad9b769048 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -99,6 +99,9 @@ /* Polling time to wait for fDeviceInit */ #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */ +/* Default RTC update every 10 seconds */ +#define UFS_RTC_UPDATE_INTERVAL_MS (10 * MSEC_PER_SEC) + /* UFSHC 4.0 compliant HC support this mode. */ static bool use_mcq_mode = true; @@ -683,6 +686,8 @@ static void ufshcd_device_reset(struct ufs_hba *hba) hba->dev_info.wb_enabled = false; hba->dev_info.wb_buf_flush_enabled = false; } + if (hba->dev_info.rtc_type == UFS_RTC_RELATIVE) + hba->dev_info.rtc_time_baseline = 0; } if (err != -EOPNOTSUPP) ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err); @@ -8188,6 +8193,72 @@ static void ufs_fixup_device_setup(struct ufs_hba *hba) ufshcd_vops_fixup_dev_quirks(hba); } +static void ufshcd_update_rtc(struct ufs_hba *hba) +{ + struct timespec64 ts64; + int err; + u32 val; + + ktime_get_real_ts64(&ts64); + + if (ts64.tv_sec < hba->dev_info.rtc_time_baseline) { + dev_warn_once(hba->dev, "%s: Current time precedes previous setting!\n", __func__); + return; + } + + /* + * The Absolute RTC mode has a 136-year limit, spanning from 2010 to 2146. If a time beyond + * 2146 is required, it is recommended to choose the relative RTC mode. + */ + val = ts64.tv_sec - hba->dev_info.rtc_time_baseline; + + ufshcd_rpm_get_sync(hba); + err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_SECONDS_PASSED, + 0, 0, &val); + ufshcd_rpm_put_sync(hba); + + if (err) + dev_err(hba->dev, "%s: Failed to update rtc %d\n", __func__, err); + else if (hba->dev_info.rtc_type == UFS_RTC_RELATIVE) + hba->dev_info.rtc_time_baseline = ts64.tv_sec; +} + +static void ufshcd_rtc_work(struct work_struct *work) +{ + struct ufs_hba *hba; + + hba = container_of(to_delayed_work(work), struct ufs_hba, ufs_rtc_update_work); + + /* Update RTC only when there are no requests in progress and UFSHCI is operational */ + if (!ufshcd_is_ufs_dev_busy(hba) && hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) + ufshcd_update_rtc(hba); + + if (ufshcd_is_ufs_dev_active(hba)) + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); +} + +static void ufs_init_rtc(struct ufs_hba *hba, u8 *desc_buf) +{ + u16 periodic_rtc_update = get_unaligned_be16(&desc_buf[DEVICE_DESC_PARAM_FRQ_RTC]); + struct ufs_dev_info *dev_info = &hba->dev_info; + + if (periodic_rtc_update & UFS_RTC_TIME_BASELINE) { + dev_info->rtc_type = UFS_RTC_ABSOLUTE; + + /* + * The concept of measuring time in Linux as the number of seconds elapsed since + * 00:00:00 UTC on January 1, 1970, and UFS ABS RTC is elapsed from January 1st + * 2010 00:00, here we need to adjust ABS baseline. + */ + dev_info->rtc_time_baseline = mktime64(2010, 1, 1, 0, 0, 0) - + mktime64(1970, 1, 1, 0, 0, 0); + } else { + dev_info->rtc_type = UFS_RTC_RELATIVE; + dev_info->rtc_time_baseline = 0; + } +} + static int ufs_get_device_desc(struct ufs_hba *hba) { int err; @@ -8240,6 +8311,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba) ufshcd_temp_notif_probe(hba, desc_buf); + ufs_init_rtc(hba, desc_buf); + if (hba->ext_iid_sup) ufshcd_ext_iid_probe(hba, desc_buf); @@ -8793,6 +8866,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) ufshcd_force_reset_auto_bkops(hba); ufshcd_set_timestamp_attr(hba); + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); /* Gear up to HS gear if supported */ if (hba->max_pwr_info.is_valid) { @@ -9749,6 +9824,8 @@ vops_suspend: ret = ufshcd_vops_suspend(hba, pm_op, POST_CHANGE); if (ret) goto set_link_active; + + cancel_delayed_work_sync(&hba->ufs_rtc_update_work); goto out; set_link_active: @@ -9843,6 +9920,8 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto set_old_link_state; ufshcd_set_timestamp_attr(hba); + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); } if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) @@ -10539,8 +10618,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE); - INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work, - ufshcd_rpm_dev_flush_recheck_work); + INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work, ufshcd_rpm_dev_flush_recheck_work); + INIT_DELAYED_WORK(&hba->ufs_rtc_update_work, ufshcd_rtc_work); /* Set the default auto-hiberate idle timer value to 150 ms */ if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) { -- cgit From 838f595a567257e3ac0ac33cdb6bb644ca326cc1 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 12 Dec 2023 23:08:25 +0100 Subject: scsi: ufs: core: Add sysfs node for UFS RTC update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a sysfs node named 'rtc_update_ms' within the kernel, enabling user to adjust the RTC periodic update frequency to suit the specific requirements of the system and UFS. Also, this patch allows the user to disable/enable periodic update RTC in the UFS idle time. Signed-off-by: Bean Huo Link: https://lore.kernel.org/r/20231212220825.85255-4-beanhuo@iokpp.de Acked-by: Avri Altman Reviewed-by: Thomas Weißschuh Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufs-sysfs.c | 31 +++++++++++++++++++++++++++++++ drivers/ufs/core/ufshcd.c | 11 +++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index c95906443d5f..4ead1e3bdb12 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -255,6 +255,35 @@ out: return res < 0 ? res : count; } +static ssize_t rtc_update_ms_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", hba->dev_info.rtc_update_period); +} + +static ssize_t rtc_update_ms_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned int ms; + bool resume_period_update = false; + + if (kstrtouint(buf, 0, &ms)) + return -EINVAL; + + if (!hba->dev_info.rtc_update_period && ms > 0) + resume_period_update = true; + /* Minimum and maximum update frequency should be synchronized with all UFS vendors */ + hba->dev_info.rtc_update_period = ms; + + if (resume_period_update) + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(hba->dev_info.rtc_update_period)); + return count; +} + static ssize_t enable_wb_buf_flush_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -339,6 +368,7 @@ static DEVICE_ATTR_RW(auto_hibern8); static DEVICE_ATTR_RW(wb_on); static DEVICE_ATTR_RW(enable_wb_buf_flush); static DEVICE_ATTR_RW(wb_flush_threshold); +static DEVICE_ATTR_RW(rtc_update_ms); static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_rpm_lvl.attr, @@ -351,6 +381,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_wb_on.attr, &dev_attr_enable_wb_buf_flush.attr, &dev_attr_wb_flush_threshold.attr, + &dev_attr_rtc_update_ms.attr, NULL }; diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 99ad9b769048..5c4ef4b072c3 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8233,9 +8233,9 @@ static void ufshcd_rtc_work(struct work_struct *work) if (!ufshcd_is_ufs_dev_busy(hba) && hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) ufshcd_update_rtc(hba); - if (ufshcd_is_ufs_dev_active(hba)) + if (ufshcd_is_ufs_dev_active(hba) && hba->dev_info.rtc_update_period) schedule_delayed_work(&hba->ufs_rtc_update_work, - msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); + msecs_to_jiffies(hba->dev_info.rtc_update_period)); } static void ufs_init_rtc(struct ufs_hba *hba, u8 *desc_buf) @@ -8257,6 +8257,13 @@ static void ufs_init_rtc(struct ufs_hba *hba, u8 *desc_buf) dev_info->rtc_type = UFS_RTC_RELATIVE; dev_info->rtc_time_baseline = 0; } + + /* + * We ignore TIME_PERIOD defined in wPeriodicRTCUpdate because Spec does not clearly state + * how to calculate the specific update period for each time unit. And we disable periodic + * RTC update work, let user configure by sysfs node according to specific circumstance. + */ + dev_info->rtc_update_period = 0; } static int ufs_get_device_desc(struct ufs_hba *hba) -- cgit From 24db9626baedf9520f13af58cc5c02756721ec04 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 18 Dec 2023 20:23:57 -0500 Subject: scsi: ufs: host: Fix kernel-doc warning Commit fa3dca8251c4 ("scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params") inadvertently introduced a comment line without '*' prefix. Format the comment section correctly. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312171915.YhlTLvLL-lkp@intel.com/ Fixes: fa3dca8251c4 ("scsi: ufs: host: Rename structure ufs_dev_params to ufs_host_params") Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufshcd-pltfrm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index 1633edc65689..2df9fc87cd98 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -286,7 +286,7 @@ static int ufshcd_parse_operating_points(struct ufs_hba *hba) /** * ufshcd_negotiate_pwr_params - find power mode settings that are supported by - both the controller and the device + * both the controller and the device * @host_params: pointer to host parameters * @dev_max: pointer to device attributes * @agreed_pwr: returned agreed attributes -- cgit From 26cdd6940c94cbd81cc524093bd689b061df58c4 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Thu, 14 Dec 2023 18:25:32 +0530 Subject: scsi: ufs: qcom: Fix ESI vector mask While cleaning up the code to use ufshcd_rmwl() helper, the ESI vector mask was changed incorrectly. Fix it and also define a proper macro for the value together with FIELD_PREP(). Reported-by: Andrew Halaney Fixes: 0e9f4375db1c ("scsi: ufs: qcom: Use ufshcd_rmwl() where applicable") Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20231214125532.55109-1-manivannan.sadhasivam@linaro.org Reviewed-by: Konrad Dybcio Signed-off-by: Martin K. Petersen --- drivers/ufs/host/ufs-qcom.c | 4 +++- drivers/ufs/host/ufs-qcom.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index d5cca5d3a98f..9fd8d737edea 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -1744,7 +1744,9 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) } else { if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 && host->hw_ver.step == 0) - ufshcd_rmwl(hba, ESI_VEC_MASK, 0x1f00, REG_UFS_CFG3); + ufshcd_rmwl(hba, ESI_VEC_MASK, + FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1), + REG_UFS_CFG3); ufshcd_mcq_enable_esi(hba); } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 9026fe243307..9dd9a391ebb7 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -15,6 +15,7 @@ #define HBRN8_POLL_TOUT_MS 100 #define DEFAULT_CLK_RATE_HZ 1000000 #define MAX_SUPP_MAC 64 +#define MAX_ESI_VEC 32 #define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28) #define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) -- cgit From bdf5c0bb4dd9e7a8a4423643e6c73a7114bd58d8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 14 Dec 2023 11:23:57 -0800 Subject: scsi: ufs: core: Rename ufshcd_auto_hibern8_enable() and make it static Rename ufshcd_auto_hibern8_enable() into ufshcd_configure_auto_hibern8() since this function can enable or disable auto-hibernation. Since ufshcd_auto_hibern8_enable() is only used inside the UFSHCI driver core, declare it static. Additionally, move the definition of this function to just before its first caller. Suggested-by: Bao D. Nguyen Reviewed-by: Bao D. Nguyen Reviewed-by: Can Guo Cc: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20231214192416.3638077-2-bvanassche@acm.org Reviewed-by: Peter Wang Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 219ba7b0501b..608dba595beb 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4413,6 +4413,14 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_uic_hibern8_exit); +static void ufshcd_configure_auto_hibern8(struct ufs_hba *hba) +{ + if (!ufshcd_is_auto_hibern8_supported(hba)) + return; + + ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); +} + void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) { unsigned long flags; @@ -4432,21 +4440,13 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) !pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) { ufshcd_rpm_get_sync(hba); ufshcd_hold(hba); - ufshcd_auto_hibern8_enable(hba); + ufshcd_configure_auto_hibern8(hba); ufshcd_release(hba); ufshcd_rpm_put_sync(hba); } } EXPORT_SYMBOL_GPL(ufshcd_auto_hibern8_update); -void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) -{ - if (!ufshcd_is_auto_hibern8_supported(hba)) - return; - - ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); -} - /** * ufshcd_init_pwr_info - setting the POR (power on reset) * values in hba power info @@ -8953,8 +8953,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) if (hba->ee_usr_mask) ufshcd_write_ee_control(hba); - /* Enable Auto-Hibernate if configured */ - ufshcd_auto_hibern8_enable(hba); + ufshcd_configure_auto_hibern8(hba); out: spin_lock_irqsave(hba->host->host_lock, flags); @@ -9956,8 +9955,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) cancel_delayed_work(&hba->rpm_dev_flush_recheck_work); } - /* Enable Auto-Hibernate if configured */ - ufshcd_auto_hibern8_enable(hba); + ufshcd_configure_auto_hibern8(hba); goto out; -- cgit From 45a2c87f28ad0ee8c286bb6dd5686bc54f5b7160 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 14 Dec 2023 11:23:58 -0800 Subject: scsi: ufs: core: Simplify ufshcd_auto_hibern8_update() Calls to ufshcd_auto_hibern8_update() are already serialized: this function is either called if user space software is not running (preparing to suspend) or from a single sysfs store callback function. Kernfs serializes sysfs .store() callbacks. No functionality is changed. Reviewed-by: Bao D. Nguyen Reviewed-by: Can Guo Cc: Avri Altman Signed-off-by: Bart Van Assche Link: https://lore.kernel.org/r/20231214192416.3638077-3-bvanassche@acm.org Signed-off-by: Martin K. Petersen --- drivers/ufs/core/ufshcd.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/ufs') diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 608dba595beb..d6ae5d17892c 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -4423,21 +4423,13 @@ static void ufshcd_configure_auto_hibern8(struct ufs_hba *hba) void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) { - unsigned long flags; - bool update = false; + const u32 cur_ahit = READ_ONCE(hba->ahit); - if (!ufshcd_is_auto_hibern8_supported(hba)) + if (!ufshcd_is_auto_hibern8_supported(hba) || cur_ahit == ahit) return; - spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->ahit != ahit) { - hba->ahit = ahit; - update = true; - } - spin_unlock_irqrestore(hba->host->host_lock, flags); - - if (update && - !pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) { + WRITE_ONCE(hba->ahit, ahit); + if (!pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) { ufshcd_rpm_get_sync(hba); ufshcd_hold(hba); ufshcd_configure_auto_hibern8(hba); -- cgit