|
|
@@ -744,6 +744,8 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
|
|
|
if (!ufshcd_is_clkgating_allowed(hba))
|
|
|
return;
|
|
|
device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
|
|
|
+ cancel_work_sync(&hba->clk_gating.ungate_work);
|
|
|
+ cancel_delayed_work_sync(&hba->clk_gating.gate_work);
|
|
|
}
|
|
|
|
|
|
/* Must be called with host lock acquired */
|
|
|
@@ -2246,6 +2248,22 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * ufshcd_init_pwr_info - setting the POR (power on reset)
|
|
|
+ * values in hba power info
|
|
|
+ * @hba: per-adapter instance
|
|
|
+ */
|
|
|
+static void ufshcd_init_pwr_info(struct ufs_hba *hba)
|
|
|
+{
|
|
|
+ hba->pwr_info.gear_rx = UFS_PWM_G1;
|
|
|
+ hba->pwr_info.gear_tx = UFS_PWM_G1;
|
|
|
+ hba->pwr_info.lane_rx = 1;
|
|
|
+ hba->pwr_info.lane_tx = 1;
|
|
|
+ hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
|
|
|
+ hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
|
|
|
+ hba->pwr_info.hs_rate = 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
|
|
|
* @hba: per-adapter instance
|
|
|
@@ -2844,8 +2862,13 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
|
|
|
hba = shost_priv(sdev->host);
|
|
|
scsi_deactivate_tcq(sdev, hba->nutrs);
|
|
|
/* Drop the reference as it won't be needed anymore */
|
|
|
- if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN)
|
|
|
+ if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(hba->host->host_lock, flags);
|
|
|
hba->sdev_ufs_device = NULL;
|
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -4062,6 +4085,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
|
|
|
static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
+ struct scsi_device *sdev_rpmb;
|
|
|
+ struct scsi_device *sdev_boot;
|
|
|
|
|
|
hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
|
|
|
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
|
|
|
@@ -4070,56 +4095,33 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
|
|
|
hba->sdev_ufs_device = NULL;
|
|
|
goto out;
|
|
|
}
|
|
|
+ scsi_device_put(hba->sdev_ufs_device);
|
|
|
|
|
|
- hba->sdev_boot = __scsi_add_device(hba->host, 0, 0,
|
|
|
+ sdev_boot = __scsi_add_device(hba->host, 0, 0,
|
|
|
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
|
|
|
- if (IS_ERR(hba->sdev_boot)) {
|
|
|
- ret = PTR_ERR(hba->sdev_boot);
|
|
|
- hba->sdev_boot = NULL;
|
|
|
+ if (IS_ERR(sdev_boot)) {
|
|
|
+ ret = PTR_ERR(sdev_boot);
|
|
|
goto remove_sdev_ufs_device;
|
|
|
}
|
|
|
+ scsi_device_put(sdev_boot);
|
|
|
|
|
|
- hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
|
|
|
+ sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
|
|
|
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
|
|
|
- if (IS_ERR(hba->sdev_rpmb)) {
|
|
|
- ret = PTR_ERR(hba->sdev_rpmb);
|
|
|
- hba->sdev_rpmb = NULL;
|
|
|
+ if (IS_ERR(sdev_rpmb)) {
|
|
|
+ ret = PTR_ERR(sdev_rpmb);
|
|
|
goto remove_sdev_boot;
|
|
|
}
|
|
|
+ scsi_device_put(sdev_rpmb);
|
|
|
goto out;
|
|
|
|
|
|
remove_sdev_boot:
|
|
|
- scsi_remove_device(hba->sdev_boot);
|
|
|
+ scsi_remove_device(sdev_boot);
|
|
|
remove_sdev_ufs_device:
|
|
|
scsi_remove_device(hba->sdev_ufs_device);
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
|
|
|
- * ufshcd_scsi_add_wlus()
|
|
|
- * @hba: per-adapter instance
|
|
|
- *
|
|
|
- */
|
|
|
-static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
|
|
|
-{
|
|
|
- if (hba->sdev_ufs_device) {
|
|
|
- scsi_remove_device(hba->sdev_ufs_device);
|
|
|
- hba->sdev_ufs_device = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (hba->sdev_boot) {
|
|
|
- scsi_remove_device(hba->sdev_boot);
|
|
|
- hba->sdev_boot = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (hba->sdev_rpmb) {
|
|
|
- scsi_remove_device(hba->sdev_rpmb);
|
|
|
- hba->sdev_rpmb = NULL;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* ufshcd_probe_hba - probe hba to detect device and initialize
|
|
|
* @hba: per-adapter instance
|
|
|
@@ -4134,6 +4136,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|
|
|
+ ufshcd_init_pwr_info(hba);
|
|
|
+
|
|
|
/* UniPro link is active now */
|
|
|
ufshcd_set_link_active(hba);
|
|
|
|
|
|
@@ -4264,12 +4268,18 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
|
|
|
static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
|
|
|
struct ufs_vreg *vreg)
|
|
|
{
|
|
|
+ if (!vreg)
|
|
|
+ return 0;
|
|
|
+
|
|
|
return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
|
|
|
}
|
|
|
|
|
|
static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
|
|
|
struct ufs_vreg *vreg)
|
|
|
{
|
|
|
+ if (!vreg)
|
|
|
+ return 0;
|
|
|
+
|
|
|
return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
|
|
|
}
|
|
|
|
|
|
@@ -4471,7 +4481,7 @@ out:
|
|
|
if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
|
|
|
clk_disable_unprepare(clki->clk);
|
|
|
}
|
|
|
- } else if (!ret && on) {
|
|
|
+ } else if (on) {
|
|
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
|
|
hba->clk_gating.state = CLKS_ON;
|
|
|
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
|
|
@@ -4675,11 +4685,25 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
|
|
|
{
|
|
|
unsigned char cmd[6] = { START_STOP };
|
|
|
struct scsi_sense_hdr sshdr;
|
|
|
- struct scsi_device *sdp = hba->sdev_ufs_device;
|
|
|
+ struct scsi_device *sdp;
|
|
|
+ unsigned long flags;
|
|
|
int ret;
|
|
|
|
|
|
- if (!sdp || !scsi_device_online(sdp))
|
|
|
- return -ENODEV;
|
|
|
+ spin_lock_irqsave(hba->host->host_lock, flags);
|
|
|
+ sdp = hba->sdev_ufs_device;
|
|
|
+ if (sdp) {
|
|
|
+ ret = scsi_device_get(sdp);
|
|
|
+ if (!ret && !scsi_device_online(sdp)) {
|
|
|
+ ret = -ENODEV;
|
|
|
+ scsi_device_put(sdp);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ret = -ENODEV;
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
/*
|
|
|
* If scsi commands fail, the scsi mid-layer schedules scsi error-
|
|
|
@@ -4718,6 +4742,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
|
|
|
if (!ret)
|
|
|
hba->curr_dev_pwr_mode = pwr_mode;
|
|
|
out:
|
|
|
+ scsi_device_put(sdp);
|
|
|
hba->host->eh_noresume = 0;
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -5087,7 +5112,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
|
|
|
int ret = 0;
|
|
|
|
|
|
if (!hba || !hba->is_powered)
|
|
|
- goto out;
|
|
|
+ return 0;
|
|
|
|
|
|
if (pm_runtime_suspended(hba->dev)) {
|
|
|
if (hba->rpm_lvl == hba->spm_lvl)
|
|
|
@@ -5231,7 +5256,6 @@ EXPORT_SYMBOL(ufshcd_shutdown);
|
|
|
void ufshcd_remove(struct ufs_hba *hba)
|
|
|
{
|
|
|
scsi_remove_host(hba->host);
|
|
|
- ufshcd_scsi_remove_wlus(hba);
|
|
|
/* disable interrupts */
|
|
|
ufshcd_disable_intr(hba, hba->intr_mask);
|
|
|
ufshcd_hba_stop(hba);
|