mirror of https://github.com/torvalds/linux.git
SCSI fixes on 20251106
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 Signed-off-by: James E.J. Bottomley <James.Bottomley@HansenPartnership.com> -----BEGIN PGP SIGNATURE----- iLgEABMIAGAWIQTnYEDbdso9F2cI+arnQslM7pishQUCaQ0gPxsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMSwyLDImHGphbWVzLmJvdHRvbWxleUBoYW5zZW5wYXJ0bmVy c2hpcC5jb20ACgkQ50LJTO6YrIWCSwEAzH0qcW02Vy5mbZR8xwDIp0ft8XD0P9kq +YNPvxNEC8gA/22DaDU6KHlDGlNKpwpACzdzbh3yA694ig0eabPX9PhB =pmib -----END PGP SIGNATURE----- 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)
This commit is contained in:
commit
11a6afabb4
|
|
@ -1949,7 +1949,7 @@ static umode_t ufs_sysfs_hid_is_visible(struct kobject *kobj,
|
||||||
return hba->dev_info.hid_sup ? attr->mode : 0;
|
return hba->dev_info.hid_sup ? attr->mode : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct attribute_group ufs_sysfs_hid_group = {
|
static const struct attribute_group ufs_sysfs_hid_group = {
|
||||||
.name = "hid",
|
.name = "hid",
|
||||||
.attrs = ufs_sysfs_hid,
|
.attrs = ufs_sysfs_hid,
|
||||||
.is_visible = ufs_sysfs_hid_is_visible,
|
.is_visible = ufs_sysfs_hid_is_visible,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,5 @@ void ufs_sysfs_remove_nodes(struct device *dev);
|
||||||
|
|
||||||
extern const struct attribute_group ufs_sysfs_unit_descriptor_group;
|
extern const struct attribute_group ufs_sysfs_unit_descriptor_group;
|
||||||
extern const struct attribute_group ufs_sysfs_lun_attributes_group;
|
extern const struct attribute_group ufs_sysfs_lun_attributes_group;
|
||||||
extern const struct attribute_group ufs_sysfs_hid_group;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -5066,7 +5066,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
|
||||||
* If UFS device isn't active then we will have to issue link startup
|
* If UFS device isn't active then we will have to issue link startup
|
||||||
* 2 times to make sure the device state move to active.
|
* 2 times to make sure the device state move to active.
|
||||||
*/
|
*/
|
||||||
if (!ufshcd_is_ufs_dev_active(hba))
|
if (!(hba->quirks & UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE) &&
|
||||||
|
!ufshcd_is_ufs_dev_active(hba))
|
||||||
link_startup_again = true;
|
link_startup_again = true;
|
||||||
|
|
||||||
link_startup:
|
link_startup:
|
||||||
|
|
@ -5131,12 +5132,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
|
||||||
ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
|
ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
|
||||||
ret = ufshcd_make_hba_operational(hba);
|
ret = ufshcd_make_hba_operational(hba);
|
||||||
out:
|
out:
|
||||||
if (ret) {
|
if (ret)
|
||||||
dev_err(hba->dev, "link startup failed %d\n", ret);
|
dev_err(hba->dev, "link startup failed %d\n", ret);
|
||||||
ufshcd_print_host_state(hba);
|
|
||||||
ufshcd_print_pwr_info(hba);
|
|
||||||
ufshcd_print_evt_hist(hba);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8503,8 +8500,6 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
|
||||||
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP) &
|
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP) &
|
||||||
UFS_DEV_HID_SUPPORT;
|
UFS_DEV_HID_SUPPORT;
|
||||||
|
|
||||||
sysfs_update_group(&hba->dev->kobj, &ufs_sysfs_hid_group);
|
|
||||||
|
|
||||||
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
|
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
|
||||||
|
|
||||||
err = ufshcd_read_string_desc(hba, model_index,
|
err = ufshcd_read_string_desc(hba, model_index,
|
||||||
|
|
@ -10661,7 +10656,7 @@ static int ufshcd_add_scsi_host(struct ufs_hba *hba)
|
||||||
* @mmio_base: base register address
|
* @mmio_base: base register address
|
||||||
* @irq: Interrupt line of device
|
* @irq: Interrupt line of device
|
||||||
*
|
*
|
||||||
* Return: 0 on success, non-zero value on failure.
|
* Return: 0 on success; < 0 on failure.
|
||||||
*/
|
*/
|
||||||
int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
|
int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
|
||||||
{
|
{
|
||||||
|
|
@ -10891,8 +10886,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_disable;
|
goto out_disable;
|
||||||
|
|
||||||
async_schedule(ufshcd_async_scan, hba);
|
|
||||||
ufs_sysfs_add_nodes(hba->dev);
|
ufs_sysfs_add_nodes(hba->dev);
|
||||||
|
async_schedule(ufshcd_async_scan, hba);
|
||||||
|
|
||||||
device_enable_async_suspend(dev);
|
device_enable_async_suspend(dev);
|
||||||
ufshcd_pm_qos_init(hba);
|
ufshcd_pm_qos_init(hba);
|
||||||
|
|
@ -10902,7 +10897,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
|
||||||
hba->is_irq_enabled = false;
|
hba->is_irq_enabled = false;
|
||||||
ufshcd_hba_exit(hba);
|
ufshcd_hba_exit(hba);
|
||||||
out_error:
|
out_error:
|
||||||
return err;
|
return err > 0 ? -EIO : err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ufshcd_init);
|
EXPORT_SYMBOL_GPL(ufshcd_init);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -740,8 +740,21 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
|
||||||
|
|
||||||
|
|
||||||
/* reset the connected UFS device during power down */
|
/* reset the connected UFS device during power down */
|
||||||
if (ufs_qcom_is_link_off(hba) && host->device_reset)
|
if (ufs_qcom_is_link_off(hba) && host->device_reset) {
|
||||||
ufs_qcom_device_reset_ctrl(hba, true);
|
ufs_qcom_device_reset_ctrl(hba, true);
|
||||||
|
/*
|
||||||
|
* After sending the SSU command, asserting the rst_n
|
||||||
|
* line causes the device firmware to wake up and
|
||||||
|
* execute its reset routine.
|
||||||
|
*
|
||||||
|
* During this process, the device may draw current
|
||||||
|
* beyond the permissible limit for low-power mode (LPM).
|
||||||
|
* A 10ms delay, based on experimental observations,
|
||||||
|
* allows the UFS device to complete its hardware reset
|
||||||
|
* before transitioning the power rail to LPM.
|
||||||
|
*/
|
||||||
|
usleep_range(10000, 11000);
|
||||||
|
}
|
||||||
|
|
||||||
return ufs_qcom_ice_suspend(host);
|
return ufs_qcom_ice_suspend(host);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/uuid.h>
|
#include <linux/uuid.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
|
@ -31,6 +32,7 @@ struct intel_host {
|
||||||
u32 dsm_fns;
|
u32 dsm_fns;
|
||||||
u32 active_ltr;
|
u32 active_ltr;
|
||||||
u32 idle_ltr;
|
u32 idle_ltr;
|
||||||
|
int saved_spm_lvl;
|
||||||
struct dentry *debugfs_root;
|
struct dentry *debugfs_root;
|
||||||
struct gpio_desc *reset_gpio;
|
struct gpio_desc *reset_gpio;
|
||||||
};
|
};
|
||||||
|
|
@ -347,6 +349,7 @@ static int ufs_intel_common_init(struct ufs_hba *hba)
|
||||||
host = devm_kzalloc(hba->dev, sizeof(*host), GFP_KERNEL);
|
host = devm_kzalloc(hba->dev, sizeof(*host), GFP_KERNEL);
|
||||||
if (!host)
|
if (!host)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
host->saved_spm_lvl = -1;
|
||||||
ufshcd_set_variant(hba, host);
|
ufshcd_set_variant(hba, host);
|
||||||
intel_dsm_init(host, hba->dev);
|
intel_dsm_init(host, hba->dev);
|
||||||
if (INTEL_DSM_SUPPORTED(host, RESET)) {
|
if (INTEL_DSM_SUPPORTED(host, RESET)) {
|
||||||
|
|
@ -425,7 +428,8 @@ static int ufs_intel_lkf_init(struct ufs_hba *hba)
|
||||||
static int ufs_intel_adl_init(struct ufs_hba *hba)
|
static int ufs_intel_adl_init(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
hba->nop_out_timeout = 200;
|
hba->nop_out_timeout = 200;
|
||||||
hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8;
|
hba->quirks |= UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 |
|
||||||
|
UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE;
|
||||||
hba->caps |= UFSHCD_CAP_WB_EN;
|
hba->caps |= UFSHCD_CAP_WB_EN;
|
||||||
return ufs_intel_common_init(hba);
|
return ufs_intel_common_init(hba);
|
||||||
}
|
}
|
||||||
|
|
@ -538,6 +542,66 @@ static int ufshcd_pci_restore(struct device *dev)
|
||||||
|
|
||||||
return ufshcd_system_resume(dev);
|
return ufshcd_system_resume(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ufs_intel_suspend_prepare(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
struct intel_host *host = ufshcd_get_variant(hba);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only s2idle (S0ix) retains link state. Force power-off
|
||||||
|
* (UFS_PM_LVL_5) for any other case.
|
||||||
|
*/
|
||||||
|
if (pm_suspend_target_state != PM_SUSPEND_TO_IDLE && hba->spm_lvl < UFS_PM_LVL_5) {
|
||||||
|
host->saved_spm_lvl = hba->spm_lvl;
|
||||||
|
hba->spm_lvl = UFS_PM_LVL_5;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ufshcd_suspend_prepare(dev);
|
||||||
|
|
||||||
|
if (err < 0 && host->saved_spm_lvl != -1) {
|
||||||
|
hba->spm_lvl = host->saved_spm_lvl;
|
||||||
|
host->saved_spm_lvl = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ufs_intel_resume_complete(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
struct intel_host *host = ufshcd_get_variant(hba);
|
||||||
|
|
||||||
|
ufshcd_resume_complete(dev);
|
||||||
|
|
||||||
|
if (host->saved_spm_lvl != -1) {
|
||||||
|
hba->spm_lvl = host->saved_spm_lvl;
|
||||||
|
host->saved_spm_lvl = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ufshcd_pci_suspend_prepare(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (!strcmp(hba->vops->name, "intel-pci"))
|
||||||
|
return ufs_intel_suspend_prepare(dev);
|
||||||
|
|
||||||
|
return ufshcd_suspend_prepare(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ufshcd_pci_resume_complete(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ufs_hba *hba = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (!strcmp(hba->vops->name, "intel-pci")) {
|
||||||
|
ufs_intel_resume_complete(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ufshcd_resume_complete(dev);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -611,8 +675,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
|
||||||
.thaw = ufshcd_system_resume,
|
.thaw = ufshcd_system_resume,
|
||||||
.poweroff = ufshcd_system_suspend,
|
.poweroff = ufshcd_system_suspend,
|
||||||
.restore = ufshcd_pci_restore,
|
.restore = ufshcd_pci_restore,
|
||||||
.prepare = ufshcd_suspend_prepare,
|
.prepare = ufshcd_pci_suspend_prepare,
|
||||||
.complete = ufshcd_resume_complete,
|
.complete = ufshcd_pci_resume_complete,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -688,6 +688,13 @@ enum ufshcd_quirks {
|
||||||
* single doorbell mode.
|
* single doorbell mode.
|
||||||
*/
|
*/
|
||||||
UFSHCD_QUIRK_BROKEN_LSDBS_CAP = 1 << 25,
|
UFSHCD_QUIRK_BROKEN_LSDBS_CAP = 1 << 25,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This quirk indicates that DME_LINKSTARTUP should not be issued a 2nd
|
||||||
|
* time (refer link_startup_again) after the 1st time was successful,
|
||||||
|
* because it causes link startup to become unreliable.
|
||||||
|
*/
|
||||||
|
UFSHCD_QUIRK_PERFORM_LINK_STARTUP_ONCE = 1 << 26,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ufshcd_caps {
|
enum ufshcd_caps {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue