diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-16 19:02:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-16 19:02:04 -0400 |
commit | 7d69cff26ceadce8638cb65191285932a3de3d4c (patch) | |
tree | 7a23eb561e6a25fbd111af2d0152cc6f34c2cecd /drivers/scsi/ufs | |
parent | 8fa6f4974d55ad1fb0a9522c5a5cfd050a517048 (diff) | |
parent | 0351b8f81392c6dbbbb036e5c8f73ceff68726e9 (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.c | 36 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.h | 26 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 35 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 9 |
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 | */ |
699 | static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) | 695 | static 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 | |||
709 | static 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 | ||
713 | static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, | 717 | static 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 */ | ||
155 | struct ufs_hw_version { | ||
156 | u16 step; | ||
157 | u16 minor; | ||
158 | u8 major; | ||
159 | }; | ||
154 | struct ufs_qcom_host { | 160 | struct 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 | ||
188 | static 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, | |||
183 | static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); | 183 | static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); |
184 | static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); | 184 | static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); |
185 | static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); | 185 | static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); |
186 | static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); | ||
186 | static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); | 187 | static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); |
187 | static irqreturn_t ufshcd_intr(int irq, void *__hba); | 188 | static irqreturn_t ufshcd_intr(int irq, void *__hba); |
188 | static int ufshcd_config_pwr_mode(struct ufs_hba *hba, | 189 | static 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 | ||
2064 | static 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; |