From: Dolev Raviv <draviv@codeaurora.org>
To: James.Bottomley@HansenPartnership.com, hch@infradead.org
Cc: linux-scsi@vger.kernel.org, linux-scsi-owner@vger.kernel.org,
linux-arm-msm@vger.kernel.org, santoshsy@gmail.com,
Dolev Raviv <draviv@codeaurora.org>,
Yaniv Gardi <ygardi@codeaurora.org>
Subject: [PATCH V3 11/16] scsi: ufs: refactor configuring power mode
Date: Wed, 10 Sep 2014 14:54:18 +0300 [thread overview]
Message-ID: <1410350063-23267-12-git-send-email-draviv@codeaurora.org> (raw)
In-Reply-To: <1410350063-23267-1-git-send-email-draviv@codeaurora.org>
Sometimes, the device shall report its maximum power and speed
capabilities, but we might not wish to configure it to use those
maximum capabilities.
This change adds support for the vendor specific host driver to
implement power change notify callback.
To enable configuring different power modes (number of lanes,
gear number and fast/slow modes) it is necessary to split the
configuration stage from the stage that reads the device max power mode.
In addition, it is not required to read the configuration more than
once, thus the configuration is stored after reading it once.
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 79ef312..bfa9a75 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -178,6 +178,8 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
static void ufshcd_hba_exit(struct ufs_hba *hba);
static int ufshcd_probe_hba(struct ufs_hba *hba);
static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
+static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *desired_pwr_mode);
static inline void ufshcd_enable_irq(struct ufs_hba *hba)
{
@@ -1933,65 +1935,129 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
}
/**
- * ufshcd_config_max_pwr_mode - Set & Change power mode with
- * maximum capability attribute information.
- * @hba: per adapter instance
- *
- * Returns 0 on success, non-zero value on failure
+ * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
+ * @hba: per-adapter instance
*/
-static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba)
{
- enum {RX = 0, TX = 1};
- u32 lanes[] = {1, 1};
- u32 gear[] = {1, 1};
- u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
- int ret;
+ struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info;
+
+ if (hba->max_pwr_info.is_valid)
+ return 0;
+
+ pwr_info->pwr_tx = FASTAUTO_MODE;
+ pwr_info->pwr_rx = FASTAUTO_MODE;
+ pwr_info->hs_rate = PA_HS_MODE_B;
/* Get the connected lane count */
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), &lanes[RX]);
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &lanes[TX]);
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES),
+ &pwr_info->lane_rx);
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES),
+ &pwr_info->lane_tx);
+
+ if (!pwr_info->lane_rx || !pwr_info->lane_tx) {
+ dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n",
+ __func__,
+ pwr_info->lane_rx,
+ pwr_info->lane_tx);
+ return -EINVAL;
+ }
/*
* First, get the maximum gears of HS speed.
* If a zero value, it means there is no HSGEAR capability.
* Then, get the maximum gears of PWM speed.
*/
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[RX]);
- if (!gear[RX]) {
- ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), &gear[RX]);
- pwr[RX] = SLOWAUTO_MODE;
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx);
+ if (!pwr_info->gear_rx) {
+ ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+ &pwr_info->gear_rx);
+ if (!pwr_info->gear_rx) {
+ dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n",
+ __func__, pwr_info->gear_rx);
+ return -EINVAL;
+ }
+ pwr_info->pwr_rx = SLOWAUTO_MODE;
}
- ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[TX]);
- if (!gear[TX]) {
+ ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR),
+ &pwr_info->gear_tx);
+ if (!pwr_info->gear_tx) {
ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
- &gear[TX]);
- pwr[TX] = SLOWAUTO_MODE;
+ &pwr_info->gear_tx);
+ if (!pwr_info->gear_tx) {
+ dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n",
+ __func__, pwr_info->gear_tx);
+ return -EINVAL;
+ }
+ pwr_info->pwr_tx = SLOWAUTO_MODE;
}
+ hba->max_pwr_info.is_valid = true;
+ return 0;
+}
+
+/**
+ * ufshcd_config_pwr_mode - configure a new power mode
+ * @hba: per-adapter instance
+ * @desired_pwr_mode: desired power configuration
+ */
+static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
+ struct ufs_pa_layer_attr *desired_pwr_mode)
+{
+ struct ufs_pa_layer_attr final_params = { 0 };
+ int ret;
+
+ if (hba->vops->pwr_change_notify)
+ hba->vops->pwr_change_notify(hba,
+ PRE_CHANGE, desired_pwr_mode, &final_params);
+ else
+ memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
+
/*
* Configure attributes for power mode change with below.
* - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
* - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
* - PA_HSSERIES
*/
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), lanes[RX]);
- if (pwr[RX] == FASTAUTO_MODE)
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), final_params.gear_rx);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
+ final_params.lane_rx);
+ if (final_params.pwr_rx == FASTAUTO_MODE ||
+ final_params.pwr_rx == FAST_MODE)
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+ else
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE);
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), lanes[TX]);
- if (pwr[TX] == FASTAUTO_MODE)
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), final_params.gear_tx);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
+ final_params.lane_tx);
+ if (final_params.pwr_tx == FASTAUTO_MODE ||
+ final_params.pwr_tx == FAST_MODE)
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
-
- if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), PA_HS_MODE_B);
-
- ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX] << 4 | pwr[TX]);
- if (ret)
+ else
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE);
+
+ if ((final_params.pwr_rx == FASTAUTO_MODE ||
+ final_params.pwr_tx == FASTAUTO_MODE ||
+ final_params.pwr_rx == FAST_MODE ||
+ final_params.pwr_tx == FAST_MODE) &&
+ final_params.hs_rate == PA_HS_MODE_B)
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
+ final_params.hs_rate);
+
+ ret = ufshcd_uic_change_pwr_mode(hba, final_params.pwr_rx << 4
+ | final_params.pwr_tx);
+ if (ret) {
dev_err(hba->dev,
"pwr_mode: power mode change failed %d\n", ret);
+ } else {
+ if (hba->vops->pwr_change_notify)
+ hba->vops->pwr_change_notify(hba,
+ POST_CHANGE, NULL, &final_params);
+
+ memcpy(&hba->pwr_info, &final_params, sizeof(final_params));
+ }
return ret;
}
@@ -3658,7 +3724,16 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
hba->wlun_dev_clr_ua = true;
- ufshcd_config_max_pwr_mode(hba);
+ if (ufshcd_get_max_pwr_mode(hba)) {
+ dev_err(hba->dev,
+ "%s: Failed getting max supported power mode\n",
+ __func__);
+ } else {
+ ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info);
+ if (ret)
+ dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
+ __func__, ret);
+ }
/*
* If we are in error handling context or in power management callbacks
@@ -4775,6 +4850,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
host->unique_id = host->host_no;
host->max_cmd_len = MAX_CDB_SIZE;
+ hba->max_pwr_info.is_valid = false;
+
/* Initailize wait queue for task management */
init_waitqueue_head(&hba->tm_wq);
init_waitqueue_head(&hba->tm_tag_wq);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 1ee429d..caebdcb 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -221,6 +221,22 @@ struct ufs_clk_info {
#define PRE_CHANGE 0
#define POST_CHANGE 1
+
+struct ufs_pa_layer_attr {
+ u32 gear_rx;
+ u32 gear_tx;
+ u32 lane_rx;
+ u32 lane_tx;
+ u32 pwr_rx;
+ u32 pwr_tx;
+ u32 hs_rate;
+};
+
+struct ufs_pwr_mode_info {
+ bool is_valid;
+ struct ufs_pa_layer_attr info;
+};
+
/**
* struct ufs_hba_variant_ops - variant specific callbacks
* @name: variant name
@@ -232,6 +248,9 @@ struct ufs_clk_info {
* variant specific Uni-Pro initialization.
* @link_startup_notify: called before and after Link startup is carried out
* to allow variant specific Uni-Pro initialization.
+ * @pwr_change_notify: called before and after a power mode change
+ * is carried out to allow vendor spesific capabilities
+ * to be set.
* @suspend: called during host controller PM callback
* @resume: called during host controller PM callback
*/
@@ -243,6 +262,9 @@ struct ufs_hba_variant_ops {
int (*setup_regulators)(struct ufs_hba *, bool);
int (*hce_enable_notify)(struct ufs_hba *, bool);
int (*link_startup_notify)(struct ufs_hba *, bool);
+ int (*pwr_change_notify)(struct ufs_hba *,
+ bool, struct ufs_pa_layer_attr *,
+ struct ufs_pa_layer_attr *);
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
};
@@ -302,6 +324,8 @@ struct ufs_init_prefetch {
* @auto_bkops_enabled: to track whether bkops is enabled in device
* @vreg_info: UFS device voltage regulator information
* @clk_list_head: UFS host controller clocks list node head
+ * @pwr_info: holds current power mode
+ * @max_pwr_info: keeps the device max valid pwm
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -384,6 +408,9 @@ struct ufs_hba {
struct list_head clk_list_head;
bool wlun_dev_clr_ua;
+
+ struct ufs_pa_layer_attr pwr_info;
+ struct ufs_pwr_mode_info max_pwr_info;
};
#define ufshcd_writel(hba, val, reg) \
--
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
next prev parent reply other threads:[~2014-09-10 11:55 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-10 11:54 [PATCH V3 00/16] UFS: Power management support Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 01/16] scsi: support well known logical units Dolev Raviv
2014-09-10 18:58 ` Christoph Hellwig
2014-09-12 0:41 ` Subhash Jadavani
2014-09-13 18:54 ` 'Christoph Hellwig'
2014-09-18 17:18 ` Subhash Jadavani
2014-09-18 19:12 ` Subhash Jadavani
2014-09-22 14:28 ` 'Christoph Hellwig'
2014-09-23 21:40 ` Subhash Jadavani
2014-09-10 11:54 ` [PATCH V3 02/16] scsi: balance out autopm get/put calls in scsi_sysfs_add_sdev() Dolev Raviv
2014-09-13 18:54 ` Christoph Hellwig
2014-09-10 11:54 ` [PATCH V3 03/16] scsi: ufs: Allow vendor specific initialization Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 04/16] scsi: ufs: Add regulator enable support Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 05/16] scsi: ufs: Add clock initialization support Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 06/16] scsi: ufs: refactor query descriptor API support Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 07/16] scsi: ufs: improve init sequence Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 08/16] scsi: ufs: Active Power Mode - configuring bActiveICCLevel Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 09/16] scsi: ufs: introduce well known logical unit in ufs Dolev Raviv
2014-09-11 13:06 ` Akinobu Mita
2014-09-15 10:39 ` Dolev Raviv
2014-09-15 14:55 ` Akinobu Mita
2014-09-10 11:54 ` [PATCH V3 10/16] scsi: ufs: add UFS power management support Dolev Raviv
2014-09-10 13:58 ` Akinobu Mita
2014-09-15 11:09 ` Dolev Raviv
2014-09-16 13:44 ` Akinobu Mita
2014-09-18 13:02 ` Kiran Padwal
2014-09-21 14:35 ` Dolev Raviv
2014-09-10 11:54 ` Dolev Raviv [this message]
2014-09-11 13:09 ` [PATCH V3 11/16] scsi: ufs: refactor configuring power mode Akinobu Mita
2014-09-15 11:10 ` Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 12/16] scsi: ufs: Add support for clock gating Dolev Raviv
2014-09-18 13:05 ` Kiran Padwal
2014-09-10 11:54 ` [PATCH V3 13/16] scsi: ufs: Add freq-table-hz property for UFS device Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 14/16] scsi: ufs: Add support for clock scaling using devfreq framework Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 15/16] scsi: ufs: tune bkops while power managment events Dolev Raviv
2014-09-10 11:54 ` [PATCH V3 16/16] scsi: ufs: definitions for phy interface Dolev Raviv
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1410350063-23267-12-git-send-email-draviv@codeaurora.org \
--to=draviv@codeaurora.org \
--cc=James.Bottomley@HansenPartnership.com \
--cc=hch@infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-scsi-owner@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=santoshsy@gmail.com \
--cc=ygardi@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).