Commit 11a6afab authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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)
parents cff0a1be a2b32bc1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1949,7 +1949,7 @@ static umode_t ufs_sysfs_hid_is_visible(struct kobject *kobj,
	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",
	.attrs = ufs_sysfs_hid,
	.is_visible = ufs_sysfs_hid_is_visible,
+0 −1
Original line number Diff line number Diff line
@@ -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_lun_attributes_group;
extern const struct attribute_group ufs_sysfs_hid_group;

#endif
+6 −11
Original line number Diff line number Diff line
@@ -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
	 * 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:
@@ -5131,12 +5132,8 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
	ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
	ret = ufshcd_make_hba_operational(hba);
out:
	if (ret) {
	if (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;
}

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

	sysfs_update_group(&hba->dev->kobj, &ufs_sysfs_hid_group);

	model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];

	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
 * @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)
{
@@ -10891,8 +10886,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
	if (err)
		goto out_disable;

	async_schedule(ufshcd_async_scan, hba);
	ufs_sysfs_add_nodes(hba->dev);
	async_schedule(ufshcd_async_scan, hba);

	device_enable_async_suspend(dev);
	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;
	ufshcd_hba_exit(hba);
out_error:
	return err;
	return err > 0 ? -EIO : err;
}
EXPORT_SYMBOL_GPL(ufshcd_init);

+14 −1
Original line number Diff line number Diff line
@@ -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 */
	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);
		/*
		 * 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);
}
+67 −3
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/suspend.h>
#include <linux/debugfs.h>
#include <linux/uuid.h>
#include <linux/acpi.h>
@@ -31,6 +32,7 @@ struct intel_host {
	u32		dsm_fns;
	u32		active_ltr;
	u32		idle_ltr;
	int		saved_spm_lvl;
	struct dentry	*debugfs_root;
	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);
	if (!host)
		return -ENOMEM;
	host->saved_spm_lvl = -1;
	ufshcd_set_variant(hba, host);
	intel_dsm_init(host, hba->dev);
	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)
{
	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;
	return ufs_intel_common_init(hba);
}
@@ -538,6 +542,66 @@ static int ufshcd_pci_restore(struct device *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

/**
@@ -611,8 +675,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = {
	.thaw		= ufshcd_system_resume,
	.poweroff	= ufshcd_system_suspend,
	.restore	= ufshcd_pci_restore,
	.prepare	= ufshcd_suspend_prepare,
	.complete	= ufshcd_resume_complete,
	.prepare	= ufshcd_pci_suspend_prepare,
	.complete	= ufshcd_pci_resume_complete,
#endif
};

Loading