Skip to content

Commit 11a6afa

Browse files
committed
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley: "All fixes in the UFS driver. The big contributor to the diffstats is the Intel controller S0ix/S3 fix which has to special case the suspend/resume patch for intel controllers in ufshcd-pci.c" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: ufs: core: Fix invalid probe error return value scsi: ufs: ufs-pci: Set UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE for Intel ADL scsi: ufs: core: Add a quirk to suppress link_startup_again scsi: ufs: ufs-pci: Fix S0ix/S3 for Intel controllers scsi: ufs: core: Revert "Make HID attributes visible" scsi: ufs: core: Reduce link startup failure logging scsi: ufs: core: Fix a race condition related to the "hid" attribute group scsi: ufs: ufs-qcom: Fix UFS OCP issue during UFS power down (PC=3)
2 parents cff0a1b + a2b32bc commit 11a6afa

6 files changed

Lines changed: 95 additions & 17 deletions

File tree

drivers/ufs/core/ufs-sysfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1949,7 +1949,7 @@ static umode_t ufs_sysfs_hid_is_visible(struct kobject *kobj,
19491949
return hba->dev_info.hid_sup ? attr->mode : 0;
19501950
}
19511951

1952-
const struct attribute_group ufs_sysfs_hid_group = {
1952+
static const struct attribute_group ufs_sysfs_hid_group = {
19531953
.name = "hid",
19541954
.attrs = ufs_sysfs_hid,
19551955
.is_visible = ufs_sysfs_hid_is_visible,

drivers/ufs/core/ufs-sysfs.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,5 @@ void ufs_sysfs_remove_nodes(struct device *dev);
1414

1515
extern const struct attribute_group ufs_sysfs_unit_descriptor_group;
1616
extern const struct attribute_group ufs_sysfs_lun_attributes_group;
17-
extern const struct attribute_group ufs_sysfs_hid_group;
1817

1918
#endif

drivers/ufs/core/ufshcd.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5066,7 +5066,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
50665066
* If UFS device isn't active then we will have to issue link startup
50675067
* 2 times to make sure the device state move to active.
50685068
*/
5069-
if (!ufshcd_is_ufs_dev_active(hba))
5069+
if (!(hba->quirks & UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE) &&
5070+
!ufshcd_is_ufs_dev_active(hba))
50705071
link_startup_again = true;
50715072

50725073
link_startup:
@@ -5131,12 +5132,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
51315132
ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
51325133
ret = ufshcd_make_hba_operational(hba);
51335134
out:
5134-
if (ret) {
5135+
if (ret)
51355136
dev_err(hba->dev, "link startup failed %d\n", ret);
5136-
ufshcd_print_host_state(hba);
5137-
ufshcd_print_pwr_info(hba);
5138-
ufshcd_print_evt_hist(hba);
5139-
}
51405137
return ret;
51415138
}
51425139

@@ -8503,8 +8500,6 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
85038500
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP) &
85048501
UFS_DEV_HID_SUPPORT;
85058502

8506-
sysfs_update_group(&hba->dev->kobj, &ufs_sysfs_hid_group);
8507-
85088503
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
85098504

85108505
err = ufshcd_read_string_desc(hba, model_index,
@@ -10661,7 +10656,7 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba)
1066110656
* @mmio_base: base register address
1066210657
* @irq: Interrupt line of device
1066310658
*
10664-
* Return: 0 on success, non-zero value on failure.
10659+
* Return: 0 on success; < 0 on failure.
1066510660
*/
1066610661
int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1066710662
{
@@ -10891,8 +10886,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1089110886
if (err)
1089210887
goto out_disable;
1089310888

10894-
async_schedule(ufshcd_async_scan, hba);
1089510889
ufs_sysfs_add_nodes(hba->dev);
10890+
async_schedule(ufshcd_async_scan, hba);
1089610891

1089710892
device_enable_async_suspend(dev);
1089810893
ufshcd_pm_qos_init(hba);
@@ -10902,7 +10897,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1090210897
hba->is_irq_enabled = false;
1090310898
ufshcd_hba_exit(hba);
1090410899
out_error:
10905-
return err;
10900+
return err > 0 ? -EIO : err;
1090610901
}
1090710902
EXPORT_SYMBOL_GPL(ufshcd_init);
1090810903

drivers/ufs/host/ufs-qcom.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,8 +740,21 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
740740

741741

742742
/* reset the connected UFS device during power down */
743-
if (ufs_qcom_is_link_off(hba) && host->device_reset)
743+
if (ufs_qcom_is_link_off(hba) && host->device_reset) {
744744
ufs_qcom_device_reset_ctrl(hba, true);
745+
/*
746+
* After sending the SSU command, asserting the rst_n
747+
* line causes the device firmware to wake up and
748+
* execute its reset routine.
749+
*
750+
* During this process, the device may draw current
751+
* beyond the permissible limit for low-power mode (LPM).
752+
* A 10ms delay, based on experimental observations,
753+
* allows the UFS device to complete its hardware reset
754+
* before transitioning the power rail to LPM.
755+
*/
756+
usleep_range(10000, 11000);
757+
}
745758

746759
return ufs_qcom_ice_suspend(host);
747760
}

drivers/ufs/host/ufshcd-pci.c

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/pci.h>
1616
#include <linux/pm_runtime.h>
1717
#include <linux/pm_qos.h>
18+
#include <linux/suspend.h>
1819
#include <linux/debugfs.h>
1920
#include <linux/uuid.h>
2021
#include <linux/acpi.h>
@@ -31,6 +32,7 @@ struct intel_host {
3132
u32 dsm_fns;
3233
u32 active_ltr;
3334
u32 idle_ltr;
35+
int saved_spm_lvl;
3436
struct dentry *debugfs_root;
3537
struct gpio_desc *reset_gpio;
3638
};
@@ -347,6 +349,7 @@ static int ufs_intel_common_init(struct ufs_hba *hba)
347349
host = devm_kzalloc(hba->dev, sizeof(*host), GFP_KERNEL);
348350
if (!host)
349351
return -ENOMEM;
352+
host->saved_spm_lvl = -1;
350353
ufshcd_set_variant(hba, host);
351354
intel_dsm_init(host, hba->dev);
352355
if (INTEL_DSM_SUPPORTED(host, RESET)) {
@@ -425,7 +428,8 @@ static int ufs_intel_lkf_init(struct ufs_hba *hba)
425428
static int ufs_intel_adl_init(struct ufs_hba *hba)
426429
{
427430
hba->nop_out_timeout = 200;
428-
hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8;
431+
hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 |
432+
UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE;
429433
hba->caps |= UFSHCD_CAP_WB_EN;
430434
return ufs_intel_common_init(hba);
431435
}
@@ -538,6 +542,66 @@ static int ufshcd_pci_restore(struct device *dev)
538542

539543
return ufshcd_system_resume(dev);
540544
}
545+
546+
static int ufs_intel_suspend_prepare(struct device *dev)
547+
{
548+
struct ufs_hba *hba = dev_get_drvdata(dev);
549+
struct intel_host *host = ufshcd_get_variant(hba);
550+
int err;
551+
552+
/*
553+
* Only s2idle (S0ix) retains link state. Force power-off
554+
* (UFS_PM_LVL_5) for any other case.
555+
*/
556+
if (pm_suspend_target_state != PM_SUSPEND_TO_IDLE && hba->spm_lvl < UFS_PM_LVL_5) {
557+
host->saved_spm_lvl = hba->spm_lvl;
558+
hba->spm_lvl = UFS_PM_LVL_5;
559+
}
560+
561+
err = ufshcd_suspend_prepare(dev);
562+
563+
if (err < 0 && host->saved_spm_lvl != -1) {
564+
hba->spm_lvl = host->saved_spm_lvl;
565+
host->saved_spm_lvl = -1;
566+
}
567+
568+
return err;
569+
}
570+
571+
static void ufs_intel_resume_complete(struct device *dev)
572+
{
573+
struct ufs_hba *hba = dev_get_drvdata(dev);
574+
struct intel_host *host = ufshcd_get_variant(hba);
575+
576+
ufshcd_resume_complete(dev);
577+
578+
if (host->saved_spm_lvl != -1) {
579+
hba->spm_lvl = host->saved_spm_lvl;
580+
host->saved_spm_lvl = -1;
581+
}
582+
}
583+
584+
static int ufshcd_pci_suspend_prepare(struct device *dev)
585+
{
586+
struct ufs_hba *hba = dev_get_drvdata(dev);
587+
588+
if (!strcmp(hba->vops->name, "intel-pci"))
589+
return ufs_intel_suspend_prepare(dev);
590+
591+
return ufshcd_suspend_prepare(dev);
592+
}
593+
594+
static void ufshcd_pci_resume_complete(struct device *dev)
595+
{
596+
struct ufs_hba *hba = dev_get_drvdata(dev);
597+
598+
if (!strcmp(hba->vops->name, "intel-pci")) {
599+
ufs_intel_resume_complete(dev);
600+
return;
601+
}
602+
603+
ufshcd_resume_complete(dev);
604+
}
541605
#endif
542606

543607
/**
@@ -611,8 +675,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
611675
.thaw = ufshcd_system_resume,
612676
.poweroff = ufshcd_system_suspend,
613677
.restore = ufshcd_pci_restore,
614-
.prepare = ufshcd_suspend_prepare,
615-
.complete = ufshcd_resume_complete,
678+
.prepare = ufshcd_pci_suspend_prepare,
679+
.complete = ufshcd_pci_resume_complete,
616680
#endif
617681
};
618682

include/ufs/ufshcd.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,13 @@ enum ufshcd_quirks {
688688
* single doorbell mode.
689689
*/
690690
UFSHCD_QUIRK_BROKEN_LSDBS_CAP = 1 << 25,
691+
692+
/*
693+
* This quirk indicates that DME_LINKSTARTUP should not be issued a 2nd
694+
* time (refer link_startup_again) after the 1st time was successful,
695+
* because it causes link startup to become unreliable.
696+
*/
697+
UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE = 1 << 26,
691698
};
692699

693700
enum ufshcd_caps {

0 commit comments

Comments
 (0)