aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-16 19:02:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-16 19:02:04 -0400
commit7d69cff26ceadce8638cb65191285932a3de3d4c (patch)
tree7a23eb561e6a25fbd111af2d0152cc6f34c2cecd /drivers/scsi/ufs
parent8fa6f4974d55ad1fb0a9522c5a5cfd050a517048 (diff)
parent0351b8f81392c6dbbbb036e5c8f73ceff68726e9 (diff)
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "This is the usual grab bag of driver updates (lpfc, qla2xxx, storvsc, aacraid, ipr) plus an assortment of minor updates. There's also a major update to aic1542 which moves the driver into this millenium" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (106 commits) change SCSI Maintainer email sd, mmc, virtio_blk, string_helpers: fix block size units ufs: add support to allow non standard behaviours (quirks) ufs-qcom: save controller revision info in internal structure qla2xxx: Update driver version to 8.07.00.18-k qla2xxx: Restore physical port WWPN only, when port down detected for FA-WWPN port. qla2xxx: Fix virtual port configuration, when switch port is disabled/enabled. qla2xxx: Prevent multiple firmware dump collection for ISP27XX. qla2xxx: Disable Interrupt handshake for ISP27XX. qla2xxx: Add debugging info for MBX timeout. qla2xxx: Add serdes read/write support for ISP27XX qla2xxx: Add udev notification to save fw dump for ISP27XX qla2xxx: Add message for sucessful FW dump collected for ISP27XX. qla2xxx: Add support to load firmware from file for ISP 26XX/27XX. qla2xxx: Fix beacon blink for ISP27XX. qla2xxx: Increase the wait time for firmware to be ready for P3P. qla2xxx: Fix crash due to wrong casting of reg for ISP27XX. qla2xxx: Fix warnings reported by static checker. lpfc: Update version to 10.5.0.0 for upstream patch set lpfc: Update copyright to 2015 ...
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c36
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h26
-rw-r--r--drivers/scsi/ufs/ufshcd.c35
-rw-r--r--drivers/scsi/ufs/ufshcd.h9
4 files changed, 94 insertions, 12 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 9217af9bf734..6652a8171de6 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -214,8 +214,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
214 struct ufs_qcom_host *host = hba->priv; 214 struct ufs_qcom_host *host = hba->priv;
215 struct phy *phy = host->generic_phy; 215 struct phy *phy = host->generic_phy;
216 int ret = 0; 216 int ret = 0;
217 u8 major;
218 u16 minor, step;
219 bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B) 217 bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
220 ? true : false; 218 ? true : false;
221 219
@@ -224,8 +222,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
224 /* provide 1ms delay to let the reset pulse propagate */ 222 /* provide 1ms delay to let the reset pulse propagate */
225 usleep_range(1000, 1100); 223 usleep_range(1000, 1100);
226 224
227 ufs_qcom_get_controller_revision(hba, &major, &minor, &step);
228 ufs_qcom_phy_save_controller_version(phy, major, minor, step);
229 ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B); 225 ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
230 if (ret) { 226 if (ret) {
231 dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n", 227 dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
@@ -698,16 +694,24 @@ out:
698 */ 694 */
699static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) 695static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
700{ 696{
701 u8 major; 697 struct ufs_qcom_host *host = hba->priv;
702 u16 minor, step;
703 698
704 ufs_qcom_get_controller_revision(hba, &major, &minor, &step); 699 if (host->hw_ver.major == 0x1)
700 hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS;
705 701
706 /* 702 if (host->hw_ver.major >= 0x2) {
707 * TBD 703 if (!ufs_qcom_cap_qunipro(host))
708 * here we should be advertising controller quirks according to 704 /* Legacy UniPro mode still need following quirks */
709 * controller version. 705 hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS;
710 */ 706 }
707}
708
709static void ufs_qcom_set_caps(struct ufs_hba *hba)
710{
711 struct ufs_qcom_host *host = hba->priv;
712
713 if (host->hw_ver.major >= 0x2)
714 host->caps = UFS_QCOM_CAP_QUNIPRO;
711} 715}
712 716
713static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, 717static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
@@ -929,6 +933,13 @@ static int ufs_qcom_init(struct ufs_hba *hba)
929 if (err) 933 if (err)
930 goto out_host_free; 934 goto out_host_free;
931 935
936 ufs_qcom_get_controller_revision(hba, &host->hw_ver.major,
937 &host->hw_ver.minor, &host->hw_ver.step);
938
939 /* update phy revision information before calling phy_init() */
940 ufs_qcom_phy_save_controller_version(host->generic_phy,
941 host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
942
932 phy_init(host->generic_phy); 943 phy_init(host->generic_phy);
933 err = phy_power_on(host->generic_phy); 944 err = phy_power_on(host->generic_phy);
934 if (err) 945 if (err)
@@ -938,6 +949,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
938 if (err) 949 if (err)
939 goto out_disable_phy; 950 goto out_disable_phy;
940 951
952 ufs_qcom_set_caps(hba);
941 ufs_qcom_advertise_quirks(hba); 953 ufs_qcom_advertise_quirks(hba);
942 954
943 hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING; 955 hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING;
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 9a6febd007df..db2c0a00e846 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -151,7 +151,23 @@ struct ufs_qcom_bus_vote {
151 struct device_attribute max_bus_bw; 151 struct device_attribute max_bus_bw;
152}; 152};
153 153
154/* Host controller hardware version: major.minor.step */
155struct ufs_hw_version {
156 u16 step;
157 u16 minor;
158 u8 major;
159};
154struct ufs_qcom_host { 160struct ufs_qcom_host {
161
162 /*
163 * Set this capability if host controller supports the QUniPro mode
164 * and if driver wants the Host controller to operate in QUniPro mode.
165 * Note: By default this capability will be kept enabled if host
166 * controller supports the QUniPro mode.
167 */
168 #define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0)
169 u32 caps;
170
155 struct phy *generic_phy; 171 struct phy *generic_phy;
156 struct ufs_hba *hba; 172 struct ufs_hba *hba;
157 struct ufs_qcom_bus_vote bus_vote; 173 struct ufs_qcom_bus_vote bus_vote;
@@ -161,10 +177,20 @@ struct ufs_qcom_host {
161 struct clk *rx_l1_sync_clk; 177 struct clk *rx_l1_sync_clk;
162 struct clk *tx_l1_sync_clk; 178 struct clk *tx_l1_sync_clk;
163 bool is_lane_clks_enabled; 179 bool is_lane_clks_enabled;
180
181 struct ufs_hw_version hw_ver;
164}; 182};
165 183
166#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba) 184#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
167#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba) 185#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
168#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba) 186#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
169 187
188static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
189{
190 if (host->caps & UFS_QCOM_CAP_QUNIPRO)
191 return true;
192 else
193 return false;
194}
195
170#endif /* UFS_QCOM_H_ */ 196#endif /* UFS_QCOM_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2aa85e398f76..648a44675880 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -183,6 +183,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
183static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); 183static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
184static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); 184static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
185static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); 185static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
186static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
186static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); 187static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
187static irqreturn_t ufshcd_intr(int irq, void *__hba); 188static irqreturn_t ufshcd_intr(int irq, void *__hba);
188static int ufshcd_config_pwr_mode(struct ufs_hba *hba, 189static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -972,6 +973,8 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
972 973
973 ufshcd_hold(hba, false); 974 ufshcd_hold(hba, false);
974 mutex_lock(&hba->uic_cmd_mutex); 975 mutex_lock(&hba->uic_cmd_mutex);
976 ufshcd_add_delay_before_dme_cmd(hba);
977
975 spin_lock_irqsave(hba->host->host_lock, flags); 978 spin_lock_irqsave(hba->host->host_lock, flags);
976 ret = __ufshcd_send_uic_cmd(hba, uic_cmd); 979 ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
977 spin_unlock_irqrestore(hba->host->host_lock, flags); 980 spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -2058,6 +2061,37 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
2058 return ret; 2061 return ret;
2059} 2062}
2060 2063
2064static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba)
2065{
2066 #define MIN_DELAY_BEFORE_DME_CMDS_US 1000
2067 unsigned long min_sleep_time_us;
2068
2069 if (!(hba->quirks & UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS))
2070 return;
2071
2072 /*
2073 * last_dme_cmd_tstamp will be 0 only for 1st call to
2074 * this function
2075 */
2076 if (unlikely(!ktime_to_us(hba->last_dme_cmd_tstamp))) {
2077 min_sleep_time_us = MIN_DELAY_BEFORE_DME_CMDS_US;
2078 } else {
2079 unsigned long delta =
2080 (unsigned long) ktime_to_us(
2081 ktime_sub(ktime_get(),
2082 hba->last_dme_cmd_tstamp));
2083
2084 if (delta < MIN_DELAY_BEFORE_DME_CMDS_US)
2085 min_sleep_time_us =
2086 MIN_DELAY_BEFORE_DME_CMDS_US - delta;
2087 else
2088 return; /* no more delay required */
2089 }
2090
2091 /* allow sleep for extra 50us if needed */
2092 usleep_range(min_sleep_time_us, min_sleep_time_us + 50);
2093}
2094
2061/** 2095/**
2062 * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET 2096 * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
2063 * @hba: per adapter instance 2097 * @hba: per adapter instance
@@ -2157,6 +2191,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
2157 2191
2158 mutex_lock(&hba->uic_cmd_mutex); 2192 mutex_lock(&hba->uic_cmd_mutex);
2159 init_completion(&uic_async_done); 2193 init_completion(&uic_async_done);
2194 ufshcd_add_delay_before_dme_cmd(hba);
2160 2195
2161 spin_lock_irqsave(hba->host->host_lock, flags); 2196 spin_lock_irqsave(hba->host->host_lock, flags);
2162 hba->uic_async_done = &uic_async_done; 2197 hba->uic_async_done = &uic_async_done;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 4a574aa45855..b47ff07698e8 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -366,6 +366,7 @@ struct ufs_init_prefetch {
366 * @saved_err: sticky error mask 366 * @saved_err: sticky error mask
367 * @saved_uic_err: sticky UIC error mask 367 * @saved_uic_err: sticky UIC error mask
368 * @dev_cmd: ufs device management command information 368 * @dev_cmd: ufs device management command information
369 * @last_dme_cmd_tstamp: time stamp of the last completed DME command
369 * @auto_bkops_enabled: to track whether bkops is enabled in device 370 * @auto_bkops_enabled: to track whether bkops is enabled in device
370 * @vreg_info: UFS device voltage regulator information 371 * @vreg_info: UFS device voltage regulator information
371 * @clk_list_head: UFS host controller clocks list node head 372 * @clk_list_head: UFS host controller clocks list node head
@@ -416,6 +417,13 @@ struct ufs_hba {
416 unsigned int irq; 417 unsigned int irq;
417 bool is_irq_enabled; 418 bool is_irq_enabled;
418 419
420 /*
421 * delay before each dme command is required as the unipro
422 * layer has shown instabilities
423 */
424 #define UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS UFS_BIT(0)
425
426 unsigned int quirks; /* Deviations from standard UFSHCI spec. */
419 427
420 wait_queue_head_t tm_wq; 428 wait_queue_head_t tm_wq;
421 wait_queue_head_t tm_tag_wq; 429 wait_queue_head_t tm_tag_wq;
@@ -446,6 +454,7 @@ struct ufs_hba {
446 454
447 /* Device management request data */ 455 /* Device management request data */
448 struct ufs_dev_cmd dev_cmd; 456 struct ufs_dev_cmd dev_cmd;
457 ktime_t last_dme_cmd_tstamp;
449 458
450 /* Keeps information of the UFS device connected to this host */ 459 /* Keeps information of the UFS device connected to this host */
451 struct ufs_dev_info dev_info; 460 struct ufs_dev_info dev_info;