Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1256130 > unrolled thread
| Started by | Yaniv Gardi <ygardi@codeaurora.org> |
|---|---|
| First post | 2015-10-26 16:50 +0100 |
| Last post | 2015-10-28 12:50 +0100 |
| Articles | 5 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v2 00/17] add fixes, device quirks, error recovery, Yaniv Gardi <ygardi@codeaurora.org> - 2015-10-26 16:50 +0100
[PATCH v2 05/17] scsi: ufs: implement scsi host timeout handler Yaniv Gardi <ygardi@codeaurora.org> - 2015-10-26 16:50 +0100
[PATCH v2 16/17] scsi: ufs-qcom: set PA_Local_TX_LCC_Enable before link startup Yaniv Gardi <ygardi@codeaurora.org> - 2015-10-26 16:50 +0100
[PATCH v2 02/17] scsi: ufs: add option to change default UFS power management level Yaniv Gardi <ygardi@codeaurora.org> - 2015-10-26 16:50 +0100
Re: [PATCH v2 00/17] add fixes, device quirks, error recovery, "Gilad Broner" <gbroner@codeaurora.org> - 2015-10-28 12:50 +0100
| From | Yaniv Gardi <ygardi@codeaurora.org> |
|---|---|
| Date | 2015-10-26 16:50 +0100 |
| Subject | [PATCH v2 00/17] add fixes, device quirks, error recovery, |
| Message-ID | <qnSc1-1Ad-5@gated-at.bofh.it> |
V2: This series should be pushed on top of 15 patches series: "Big fixes, retries, handle a race condition" fixed and few comments. V1: This series should be pushed on top of 15 patches series: "Big fixes, retries, handle a race condition" Yaniv Gardi (17): scsi: ufs-qcom: add number of lanes per direction scsi: ufs: add option to change default UFS power management level scsi: ufs: optimize system suspend handling scsi: ufs: avoid spurious UFS host controller interrupts scsi: ufs: implement scsi host timeout handler scsi :ufs: verify hba controller hce reg value scsi: ufs: separate device and host quirks scsi: ufs: disable vccq if it's not needed by UFS device scsi: ufs: make error handling bit faster scsi: ufs: add error recovery after DL NAC error scsi: ufs: add retry for query descriptors scsi: ufs: handle non spec compliant bkops behaviour by device scsi: ufs: tune UniPro parameters to optimize hibern8 exit time scsi: ufs: fix leakage during link off state scsi: ufs: add device quirk delay before putting UFS rails in LPM scsi: ufs-qcom: set PA_Local_TX_LCC_Enable before link startup scsi: ufs-qcom: fix compilation warnings .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 11 + drivers/scsi/ufs/Makefile | 2 +- drivers/scsi/ufs/ufs-qcom.c | 163 ++++- drivers/scsi/ufs/ufs-qcom.h | 9 + drivers/scsi/ufs/ufs.h | 32 + drivers/scsi/ufs/ufs_quirks.c | 104 +++ drivers/scsi/ufs/ufs_quirks.h | 131 ++++ drivers/scsi/ufs/ufshcd-pltfrm.c | 36 +- drivers/scsi/ufs/ufshcd.c | 803 ++++++++++++++++++--- drivers/scsi/ufs/ufshcd.h | 44 +- drivers/scsi/ufs/ufshci.h | 4 + drivers/scsi/ufs/unipro.h | 22 + 12 files changed, 1217 insertions(+), 144 deletions(-) create mode 100644 drivers/scsi/ufs/ufs_quirks.c create mode 100644 drivers/scsi/ufs/ufs_quirks.h -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Yaniv Gardi <ygardi@codeaurora.org> |
|---|---|
| Date | 2015-10-26 16:50 +0100 |
| Subject | [PATCH v2 05/17] scsi: ufs: implement scsi host timeout handler |
| Message-ID | <qnSc3-1Ad-49@gated-at.bofh.it> |
| In reply to | #1256130 |
A race condition exists between request requeueing and scsi layer
error handling:
When UFS driver queuecommand returns a busy status for a request,
it will be requeued and its tag will be freed and set to -1.
At the same time it is possible that the request will timeout and
scsi layer will start error handling for it. The scsi layer reuses
the request and its tag to send error related commands to the device,
however its tag is no longer valid.
As this request was never really sent to the device, there is no
point to start error handling with the device.
Implement the scsi error handling timeout callback and bypass SCSI
error handling for request that were not actually sent to the device.
For such requests simply reset the block layer timer. Otherwise, let
SCSI layer perform the usual error handling.
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a0aac38..3aea64b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4597,6 +4597,41 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
ufshcd_probe_hba(hba);
}
+static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ struct Scsi_Host *host;
+ struct ufs_hba *hba;
+ int index;
+ bool found = false;
+
+ if (!scmd || !scmd->device || !scmd->device->host)
+ return BLK_EH_NOT_HANDLED;
+
+ host = scmd->device->host;
+ hba = shost_priv(host);
+ if (!hba)
+ return BLK_EH_NOT_HANDLED;
+
+ spin_lock_irqsave(host->host_lock, flags);
+
+ for_each_set_bit(index, &hba->outstanding_reqs, hba->nutrs) {
+ if (hba->lrb[index].cmd == scmd) {
+ found = true;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(host->host_lock, flags);
+
+ /*
+ * Bypass SCSI error handling and reset the block layer timer if this
+ * SCSI command was not actually dispatched to UFS driver, otherwise
+ * let SCSI layer handle the error as usual.
+ */
+ return found ? BLK_EH_NOT_HANDLED : BLK_EH_RESET_TIMER;
+}
+
static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
@@ -4609,6 +4644,7 @@ static struct scsi_host_template ufshcd_driver_template = {
.eh_abort_handler = ufshcd_abort,
.eh_device_reset_handler = ufshcd_eh_device_reset_handler,
.eh_host_reset_handler = ufshcd_eh_host_reset_handler,
+ .eh_timed_out = ufshcd_eh_timed_out,
.this_id = -1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
--
1.8.5.2
--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Yaniv Gardi <ygardi@codeaurora.org> |
|---|---|
| Date | 2015-10-26 16:50 +0100 |
| Subject | [PATCH v2 16/17] scsi: ufs-qcom: set PA_Local_TX_LCC_Enable before link startup |
| Message-ID | <qnSc3-1Ad-51@gated-at.bofh.it> |
| In reply to | #1256130 |
Some UFS devices (and may be host) have issues if LCC is
enabled. So we are setting PA_Local_TX_LCC_Enable to 0
before link startup which will make sure that both host
and device TX LCC are disabled once link startup is
completed.
This change also:
- enables the device ref clock before changing to HS mode
and disables it if entered to PWM mode
- adds printouts of testbus debug registers
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
---
drivers/scsi/ufs/ufs-qcom.c | 116 +++++++++++++++++++++++++++++++++++++++++---
drivers/scsi/ufs/ufs-qcom.h | 9 ++++
drivers/scsi/ufs/ufshcd.h | 9 ++++
drivers/scsi/ufs/unipro.h | 1 +
4 files changed, 128 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index c470c40..72b0ef7 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -16,8 +16,8 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
-
#include <linux/phy/phy-qcom-ufs.h>
+
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
#include "unipro.h"
@@ -58,6 +58,12 @@ static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
len * 4, false);
}
+static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len,
+ char *prefix, void *priv)
+{
+ ufs_qcom_dump_regs(hba, offset, len, prefix);
+}
+
static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
{
int err = 0;
@@ -106,9 +112,11 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
if (!host->is_lane_clks_enabled)
return;
- clk_disable_unprepare(host->tx_l1_sync_clk);
+ if (host->hba->lanes_per_direction > 1)
+ clk_disable_unprepare(host->tx_l1_sync_clk);
clk_disable_unprepare(host->tx_l0_sync_clk);
- clk_disable_unprepare(host->rx_l1_sync_clk);
+ if (host->hba->lanes_per_direction > 1)
+ clk_disable_unprepare(host->rx_l1_sync_clk);
clk_disable_unprepare(host->rx_l0_sync_clk);
host->is_lane_clks_enabled = false;
@@ -271,9 +279,8 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
if (ret) {
- dev_err(hba->dev,
- "%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n",
- __func__, ret);
+ dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
+ __func__, ret);
goto out;
}
@@ -523,6 +530,18 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba,
150);
+ /*
+ * Some UFS devices (and may be host) have issues if LCC is
+ * enabled. So we are setting PA_Local_TX_LCC_Enable to 0
+ * before link startup which will make sure that both host
+ * and device TX LCC are disabled once link startup is
+ * completed.
+ */
+ if (ufshcd_get_local_unipro_ver(hba) != UFS_UNIPRO_VER_1_41)
+ err = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
+ 0);
+
break;
case POST_CHANGE:
ufs_qcom_link_startup_post_change(hba);
@@ -966,6 +985,10 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
goto out;
}
+ /* enable the device ref clock before changing to HS mode */
+ if (!ufshcd_is_hs_mode(&hba->pwr_info) &&
+ ufshcd_is_hs_mode(dev_req_params))
+ ufs_qcom_dev_ref_clk_ctrl(host, true);
break;
case POST_CHANGE:
if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
@@ -993,6 +1016,11 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
memcpy(&host->dev_req_params,
dev_req_params, sizeof(*dev_req_params));
ufs_qcom_update_bus_bw_vote(host);
+
+ /* disable the device ref clock if entered PWM mode */
+ if (ufshcd_is_hs_mode(&hba->pwr_info) &&
+ !ufshcd_is_hs_mode(dev_req_params))
+ ufs_qcom_dev_ref_clk_ctrl(host, false);
break;
default:
ret = -EINVAL;
@@ -1094,6 +1122,9 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
goto out;
}
+ /* enable the device ref clock for HS mode*/
+ if (ufshcd_is_hs_mode(&hba->pwr_info))
+ ufs_qcom_dev_ref_clk_ctrl(host, true);
vote = host->bus_vote.saved_vote;
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
@@ -1371,6 +1402,74 @@ out:
return err;
}
+static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba,
+ void *priv, void (*print_fn)(struct ufs_hba *hba,
+ int offset, int num_regs, char *str, void *priv))
+{
+ u32 reg;
+ struct ufs_qcom_host *host;
+
+ if (unlikely(!hba)) {
+ pr_err("%s: hba is NULL\n", __func__);
+ return;
+ }
+ if (unlikely(!print_fn)) {
+ dev_err(hba->dev, "%s: print_fn is NULL\n", __func__);
+ return;
+ }
+
+ host = ufshcd_get_variant(hba);
+ if (!(host->dbg_print_en & UFS_QCOM_DBG_PRINT_REGS_EN))
+ return;
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_REG_OCSC);
+ print_fn(hba, reg, 44, "UFS_UFS_DBG_RD_REG_OCSC ", priv);
+
+ reg = ufshcd_readl(hba, REG_UFS_CFG1);
+ reg |= UFS_BIT(17);
+ ufshcd_writel(hba, reg, REG_UFS_CFG1);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_EDTL_RAM);
+ print_fn(hba, reg, 32, "UFS_UFS_DBG_RD_EDTL_RAM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_DESC_RAM);
+ print_fn(hba, reg, 128, "UFS_UFS_DBG_RD_DESC_RAM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM);
+ print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
+
+ ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM);
+ print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UARM);
+ print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UARM ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TXUC);
+ print_fn(hba, reg, 48, "UFS_DBG_RD_REG_TXUC ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_RXUC);
+ print_fn(hba, reg, 27, "UFS_DBG_RD_REG_RXUC ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_DFC);
+ print_fn(hba, reg, 19, "UFS_DBG_RD_REG_DFC ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TRLUT);
+ print_fn(hba, reg, 34, "UFS_DBG_RD_REG_TRLUT ", priv);
+
+ reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_TMRLUT);
+ print_fn(hba, reg, 9, "UFS_DBG_RD_REG_TMRLUT ", priv);
+}
+
+static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
+{
+ if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+ ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
+ else
+ ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+}
+
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
{
/* provide a legal default configuration */
@@ -1479,6 +1578,7 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
ufshcd_rmwl(host->hba, mask,
(u32)host->testbus.select_minor << offset,
reg);
+ ufs_qcom_enable_test_bus(host);
ufshcd_release(host->hba);
pm_runtime_put_sync(host->hba->dev);
@@ -1495,8 +1595,10 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
+ ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
ufs_qcom_testbus_read(hba);
}
+
/**
* struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
*
@@ -1541,7 +1643,7 @@ static int ufs_qcom_probe(struct platform_device *pdev)
* ufs_qcom_remove - set driver_data of the device to NULL
* @pdev: pointer to platform device handle
*
- * Always return 0
+ * Always returns 0
*/
static int ufs_qcom_remove(struct platform_device *pdev)
{
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 36249b3..a19307a 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -241,6 +241,15 @@ struct ufs_qcom_host {
struct ufs_qcom_testbus testbus;
};
+static inline u32
+ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg)
+{
+ if (host->hw_ver.major <= 0x02)
+ return UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(reg);
+
+ return UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(reg);
+};
+
#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index aa1f3e5..cba580c 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -54,6 +54,7 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
+#include "unipro.h"
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -689,6 +690,14 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
+static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
+{
+ return (pwr_info->pwr_rx == FAST_MODE ||
+ pwr_info->pwr_rx == FASTAUTO_MODE) &&
+ (pwr_info->pwr_tx == FAST_MODE ||
+ pwr_info->pwr_tx == FASTAUTO_MODE);
+}
+
#define ASCII_STD true
int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 8082020..e2854e4 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -75,6 +75,7 @@
#define PA_MAXRXSPEEDFAST 0x1541
#define PA_MAXRXSPEEDSLOW 0x1542
#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_LOCAL_TX_LCC_ENABLE 0x155E
#define PA_TXSPEEDFAST 0x1565
#define PA_TXSPEEDSLOW 0x1566
#define PA_REMOTEVERINFO 0x15A0
--
1.8.5.2
--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Yaniv Gardi <ygardi@codeaurora.org> |
|---|---|
| Date | 2015-10-26 16:50 +0100 |
| Subject | [PATCH v2 02/17] scsi: ufs: add option to change default UFS power management level |
| Message-ID | <qnSc2-1Ad-27@gated-at.bofh.it> |
| In reply to | #1256130 |
UFS device and link can be put in multiple different low power modes
hence UFS driver supports multiple different low power modes.
By default UFS driver selects the default (optimal) low power mode
(which gives moderate power savings and have relatively less enter
and exit latencies) but we might have to tune this default power
mode for different chipset platforms to meet the low power
requirements/goals. Hence this patch adds option to change default
UFS low power mode (level).
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
---
.../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 8 +++++
drivers/scsi/ufs/ufshcd-pltfrm.c | 17 +++++++++-
drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++++
drivers/scsi/ufs/ufshcd.h | 4 +--
4 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 9fea0de..b7db1c9 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -38,6 +38,14 @@ Optional properties:
defined or a value in the array is "0" then it is assumed
that the frequency is set by the parent clock or a
fixed rate clock source.
+- rpm-level : UFS Runtime power management level. Following PM levels are supported:
+ 0 - Both UFS device and Link in active state (Highest power consumption)
+ 1 - UFS device in active state but Link in Hibern8 state
+ 2 - UFS device in Sleep state but Link in active state
+ 3 - UFS device in Sleep state and Link in hibern8 state (default PM level)
+ 4 - UFS device in Power-down state and Link in Hibern8 state
+ 5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption)
+- spm-level : UFS System power management level. Allowed PM levels are same as rpm-level.
- lanes-per-direction: number of lanes available per direction - either 1 or 2.
Note that it is assume same number of lanes is used both directions at once.
If not specified, default is 2 lanes per direction.
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5be0c91..1130dd9 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -226,7 +226,20 @@ out:
return err;
}
-#ifdef CONFIG_PM
+static void ufshcd_parse_pm_levels(struct ufs_hba *hba)
+{
+ struct device *dev = hba->dev;
+ struct device_node *np = dev->of_node;
+
+ if (np) {
+ if (of_property_read_u32(np, "rpm-level", &hba->rpm_lvl))
+ hba->rpm_lvl = -1;
+ if (of_property_read_u32(np, "spm-level", &hba->spm_lvl))
+ hba->spm_lvl = -1;
+ }
+}
+
+#ifdef CONFIG_SMP
/**
* ufshcd_pltfrm_suspend - suspend power management function
* @dev: pointer to device handle
@@ -345,6 +358,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
goto dealloc_host;
}
+ ufshcd_parse_pm_levels(hba);
+
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8d16aca..20c5b5d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -187,6 +187,30 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl)
return ufs_pm_lvl_states[lvl].link_state;
}
+static inline enum ufs_pm_level
+ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
+ enum uic_link_state link_state)
+{
+ enum ufs_pm_level lvl;
+
+ for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) {
+ if ((ufs_pm_lvl_states[lvl].dev_state == dev_state) &&
+ (ufs_pm_lvl_states[lvl].link_state == link_state))
+ return lvl;
+ }
+
+ /* if no match found, return the level 0 */
+ return UFS_PM_LVL_0;
+}
+
+static inline bool ufshcd_is_valid_pm_lvl(int lvl)
+{
+ if (lvl >= 0 && lvl < ARRAY_SIZE(ufs_pm_lvl_states))
+ return true;
+ else
+ return false;
+}
+
static void ufshcd_tmc_handler(struct ufs_hba *hba);
static void ufshcd_async_scan(void *data, async_cookie_t cookie);
static int ufshcd_reset_and_restore(struct ufs_hba *hba);
@@ -5885,6 +5909,21 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
hba->clk_scaling.window_start_t = 0;
}
+ /*
+ * If rpm_lvl and and spm_lvl are not already set to valid levels,
+ * set the default power management level for UFS runtime and system
+ * suspend. Default power saving mode selected is keeping UFS link in
+ * Hibern8 state and UFS device in sleep.
+ */
+ if (!ufshcd_is_valid_pm_lvl(hba->rpm_lvl))
+ hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+ UFS_SLEEP_PWR_MODE,
+ UIC_LINK_HIBERN8_STATE);
+ if (!ufshcd_is_valid_pm_lvl(hba->spm_lvl))
+ hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+ UFS_SLEEP_PWR_MODE,
+ UIC_LINK_HIBERN8_STATE);
+
/* Hold auto suspend until async scan completes */
pm_runtime_get_sync(dev);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index e7bcf65..889335a 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -408,9 +408,9 @@ struct ufs_hba {
enum ufs_dev_pwr_mode curr_dev_pwr_mode;
enum uic_link_state uic_link_state;
/* Desired UFS power management level during runtime PM */
- enum ufs_pm_level rpm_lvl;
+ int rpm_lvl;
/* Desired UFS power management level during system PM */
- enum ufs_pm_level spm_lvl;
+ int spm_lvl;
int pm_op_in_progress;
struct ufshcd_lrb *lrb;
--
1.8.5.2
--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | "Gilad Broner" <gbroner@codeaurora.org> |
|---|---|
| Date | 2015-10-28 12:50 +0100 |
| Message-ID | <qoxoS-255-3@gated-at.bofh.it> |
| In reply to | #1256130 |
Looks good to me. Reviewed-by: Gilad Broner <gbroner@codeaurora.org> > V2: > This series should be pushed on top of 15 patches series: > "Big fixes, retries, handle a race condition" > fixed and few comments. > > V1: > This series should be pushed on top of 15 patches series: > "Big fixes, retries, handle a race condition" > > Yaniv Gardi (17): > scsi: ufs-qcom: add number of lanes per direction > scsi: ufs: add option to change default UFS power management level > scsi: ufs: optimize system suspend handling > scsi: ufs: avoid spurious UFS host controller interrupts > scsi: ufs: implement scsi host timeout handler > scsi :ufs: verify hba controller hce reg value > scsi: ufs: separate device and host quirks > scsi: ufs: disable vccq if it's not needed by UFS device > scsi: ufs: make error handling bit faster > scsi: ufs: add error recovery after DL NAC error > scsi: ufs: add retry for query descriptors > scsi: ufs: handle non spec compliant bkops behaviour by device > scsi: ufs: tune UniPro parameters to optimize hibern8 exit time > scsi: ufs: fix leakage during link off state > scsi: ufs: add device quirk delay before putting UFS rails in LPM > scsi: ufs-qcom: set PA_Local_TX_LCC_Enable before link startup > scsi: ufs-qcom: fix compilation warnings > > .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 11 + > drivers/scsi/ufs/Makefile | 2 +- > drivers/scsi/ufs/ufs-qcom.c | 163 ++++- > drivers/scsi/ufs/ufs-qcom.h | 9 + > drivers/scsi/ufs/ufs.h | 32 + > drivers/scsi/ufs/ufs_quirks.c | 104 +++ > drivers/scsi/ufs/ufs_quirks.h | 131 ++++ > drivers/scsi/ufs/ufshcd-pltfrm.c | 36 +- > drivers/scsi/ufs/ufshcd.c | 803 > ++++++++++++++++++--- > drivers/scsi/ufs/ufshcd.h | 44 +- > drivers/scsi/ufs/ufshci.h | 4 + > drivers/scsi/ufs/unipro.h | 22 + > 12 files changed, 1217 insertions(+), 144 deletions(-) > create mode 100644 drivers/scsi/ufs/ufs_quirks.c > create mode 100644 drivers/scsi/ufs/ufs_quirks.h > > -- > 1.8.5.2 > > -- > QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member > of Code Aurora Forum, hosted by The Linux Foundation > -- Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web