From: Seungwon Jeon <tgih.jun@samsung.com>
To: linux-scsi@vger.kernel.org
Cc: 'Vinayak Holikatti' <vinholikatti@gmail.com>,
'Santosh Y' <santoshsy@gmail.com>,
"'James E.J. Bottomley'" <JBottomley@parallels.com>
Subject: [PATCH v4 6/6] scsi: ufs: add dme control primitives
Date: Wed, 08 May 2013 17:43:00 +0900 [thread overview]
Message-ID: <002901ce4bc8$0bdb58f0$23920ad0$%jun@samsung.com> (raw)
In-Reply-To:
Implements to support the following operations.
Currently, this patch doesn't introduce DME_ENABLE and DME_RESET
because host controller's HCE enable contains these roles.
DME_POWERON{OFF}, DME_HIBERNATE_ENTER{EXIT}, DME_ENDPOINTRESET.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
Change in v4:
- Changed function names.
drivers/scsi/ufs/ufshcd.c | 123 +++++++++++++++++++++++++++++++++++++++++++--
drivers/scsi/ufs/ufshcd.h | 26 ++++++++++
drivers/scsi/ufs/ufshci.h | 15 ++++++
3 files changed, 160 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e05eedb..45123b4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -39,6 +39,7 @@
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
UTP_TASK_REQ_COMPL |\
+ UFSHCD_HIBERNATE_MASK |\
UFSHCD_ERROR_MASK)
/* UIC command timeout, unit: ms */
#define UIC_CMD_TIMEOUT 500
@@ -203,6 +204,18 @@ static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
}
/**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+ return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
+/**
* ufshcd_free_hba_memory - Free allocated memory for LRB, request
* and task lists
* @hba: Pointer to adapter instance
@@ -1163,6 +1176,103 @@ out:
EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
/**
+ * ufshcd_dme_power_ctrl - UIC command for DME_POWERON, DME_POWEROFF
+ * @hba: per adapter instance
+ * @on: indicate wherter power_on or power_off
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_power_ctrl(struct ufs_hba *hba, u8 on)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-power-off",
+ "dme-power-on"
+ };
+ const char *power = action[!!on];
+ int ret;
+
+ uic_cmd.command = on ?
+ UIC_CMD_DME_POWERON : UIC_CMD_DME_POWEROFF;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_err(hba->dev, "%s: error code %d\n", power, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_power_ctrl);
+
+/**
+ * ufshcd_dme_hibern8_ctrl - UIC command for DME_HIBERNATE_ENTER,
+ * DME_HIBERNATE_EXIT
+ * @hba: per adapter instance
+ * @enter: indicate wherter hibernation enter or exit
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_hibern8_ctrl(struct ufs_hba *hba, u8 enter)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-hibernate-exit",
+ "dme-hibernate-enter"
+ };
+ const char *hibern8 = action[!!enter];
+ u8 status;
+ int ret;
+
+ uic_cmd.command = enter ?
+ UIC_CMD_DME_HIBER_ENTER : UIC_CMD_DME_HIBER_EXIT;
+
+ mutex_lock(&hba->uic_cmd_mutex);
+ init_completion(&hba->hibern8_done);
+ ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret) {
+ dev_err(hba->dev, "%s: error code %d\n", hibern8, ret);
+ goto out;
+ }
+
+ if (wait_for_completion_timeout(&hba->hibern8_done,
+ msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+ status = ufshcd_get_upmcrs(hba);
+ if (status != PWR_LOCAL) {
+ dev_err(hba->dev, "%s: failed, host upmcrs:0x%x\n",
+ hibern8, status);
+ ret = status;
+ }
+ } else {
+ dev_err(hba->dev, "%s: timeout\n", hibern8);
+ ret = -ETIMEDOUT;
+ }
+out:
+ mutex_unlock(&hba->uic_cmd_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_hibern8_ctrl);
+
+/**
+ * ufshcd_dme_endpoint_reset - UIC command for DME_ENDPOINTRESET
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_endpoint_reset(struct ufs_hba *hba)
+{
+ struct uic_command uic_cmd = {0};
+ int ret;
+
+ uic_cmd.command = UIC_CMD_DME_END_PT_RST;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_err(hba->dev, "dme-endpoint-reset: error code %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_endpoint_reset);
+
+/**
* ufshcd_make_hba_operational - Make UFS controller operational
* @hba: per adapter instance
*
@@ -1618,16 +1728,21 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
/**
* ufshcd_uic_cmd_compl - handle completion of uic command
* @hba: per adapter instance
+ * @intr_status: interrupt status generated by the controller
*/
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
{
- if (hba->active_uic_cmd) {
+ if ((intr_status & UIC_COMMAND_COMPL) &&
+ hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
}
+
+ if (intr_status & UFSHCD_HIBERNATE_MASK)
+ complete(&hba->hibern8_done);
}
/**
@@ -1729,8 +1844,8 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
if (hba->errors)
ufshcd_err_handler(hba);
- if (intr_status & UIC_COMMAND_COMPL)
- ufshcd_uic_cmd_compl(hba);
+ if (intr_status & UFSHCD_UIC_MASK)
+ ufshcd_uic_cmd_compl(hba, intr_status);
if (intr_status & UTP_TASK_REQ_COMPL)
ufshcd_tmc_handler(hba);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index dabd29c..0465885 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -156,6 +156,7 @@ struct ufs_query {
* @uic_cmd_mutex: mutex for uic command
* @ufshcd_tm_wait_queue: wait queue for task management
* @tm_condition: condition variable for task management
+ * @hibern8_done: completion for hibernate
* @ufshcd_state: UFSHCD states
* @intr_mask: Interrupt Mask Bits
* @feh_workq: Work queue for fatal controller error handling
@@ -195,6 +196,8 @@ struct ufs_hba {
wait_queue_head_t ufshcd_tm_wait_queue;
unsigned long tm_condition;
+ struct completion hibern8_done;
+
u32 ufshcd_state;
u32 intr_mask;
@@ -221,6 +224,9 @@ extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
u8 attr_set, u32 mib_val, u8 peer);
extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
u32 *mib_val, u8 peer);
+extern int ufshcd_dme_power_ctrl(struct ufs_hba *hba, u8 on);
+extern int ufshcd_dme_hibern8_ctrl(struct ufs_hba *hba, u8 enter);
+extern int ufshcd_dme_endpoint_reset(struct ufs_hba *hba);
/**
* ufshcd_hba_stop - Send controller to reset state
@@ -256,4 +262,24 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
return ufshcd_dme_get_attr(hba, attr_sel, mib_val, 1);
}
+static inline int ufshcd_dme_power_on(struct ufs_hba *hba)
+{
+ return ufshcd_dme_power_ctrl(hba, 1);
+}
+
+static inline int ufshcd_dme_power_off(struct ufs_hba *hba)
+{
+ return ufshcd_dme_power_ctrl(hba, 0);
+}
+
+static inline int ufshcd_dme_hibern8_enter(struct ufs_hba *hba)
+{
+ return ufshcd_dme_hibern8_ctrl(hba, 1);
+}
+
+static inline int ufshcd_dme_hibern8_exit(struct ufs_hba *hba)
+{
+ return ufshcd_dme_hibern8_ctrl(hba, 0);
+}
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index edb4d87..8ddecaa 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -124,6 +124,12 @@ enum {
#define CONTROLLER_FATAL_ERROR UFS_BIT(16)
#define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17)
+#define UFSHCD_HIBERNATE_MASK (UIC_HIBERNATE_ENTER |\
+ UIC_HIBERNATE_EXIT)
+
+#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL |\
+ UFSHCD_HIBERNATE_MASK)
+
#define UFSHCD_ERROR_MASK (UIC_ERROR |\
DEVICE_FATAL_ERROR |\
CONTROLLER_FATAL_ERROR |\
@@ -142,6 +148,15 @@ enum {
#define DEVICE_ERROR_INDICATOR UFS_BIT(5)
#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8)
+enum {
+ PWR_OK = 0x0,
+ PWR_LOCAL = 0x01,
+ PWR_REMOTE = 0x02,
+ PWR_BUSY = 0x03,
+ PWR_ERROR_CAP = 0x04,
+ PWR_FATAL_ERROR = 0x05,
+};
+
/* HCE - Host Controller Enable 34h */
#define CONTROLLER_ENABLE UFS_BIT(0)
#define CONTROLLER_DISABLE 0x0
--
1.7.0.4
next prev parent reply other threads:[~2013-05-08 8:43 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-04-24 14:14 [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU Sujit Reddy Thumma
2013-04-24 16:06 ` [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c Seungwon Jeon
2013-04-30 11:17 ` Subhash Jadavani
2013-05-01 7:46 ` merez
2013-05-02 8:11 ` Santosh Y
2013-05-02 13:37 ` Seungwon Jeon
2013-05-02 18:49 ` merez
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
2013-05-05 11:22 ` merez
2013-05-06 3:05 ` Seungwon Jeon
2013-05-06 5:37 ` [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations Seungwon Jeon
2013-05-06 10:37 ` merez
2013-05-06 19:30 ` Santosh Y
2013-05-07 3:52 ` Seungwon Jeon
2013-05-06 5:37 ` [PATCH v3 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
2013-05-06 10:39 ` merez
2013-05-06 5:37 ` [PATCH v3 3/6] scsi: ufs: fix interrupt status clears Seungwon Jeon
2013-05-06 10:49 ` merez
2013-05-06 5:37 ` [PATCH v3 4/6] scsi: ufs: rework link start-up process Seungwon Jeon
2013-05-06 9:47 ` Sujit Reddy Thumma
2013-05-06 10:36 ` merez
2013-05-06 11:21 ` Seungwon Jeon
2013-05-06 18:15 ` merez
2013-05-06 5:37 ` [PATCH v3 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
2013-05-06 19:43 ` Santosh Y
2013-05-06 5:39 ` [PATCH v3 6/6] scsi: ufs: add dme control primitives Seungwon Jeon
2013-05-06 19:51 ` Santosh Y
2013-05-07 3:45 ` Seungwon Jeon
2013-05-08 8:41 ` [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations Seungwon Jeon
2013-05-08 11:58 ` merez
2013-05-08 15:18 ` Santosh Y
2013-05-09 1:59 ` Seungwon Jeon
2013-05-09 3:27 ` Santosh Y
2013-05-09 6:39 ` Seungwon Jeon
2013-05-09 6:52 ` Santosh Y
2013-05-09 14:21 ` James Bottomley
2013-05-10 1:52 ` Seungwon Jeon
2013-05-08 8:41 ` [PATCH v4 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
2013-05-08 15:19 ` Santosh Y
2013-05-08 8:41 ` [PATCH v4 3/6] scsi: ufs: fix interrupt status clears Seungwon Jeon
2013-05-08 15:19 ` Santosh Y
2013-05-08 8:42 ` [PATCH v4 4/6] scsi: ufs: rework link start-up process Seungwon Jeon
2013-05-08 15:20 ` Santosh Y
2013-05-08 8:42 ` [PATCH v4 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
2013-05-09 6:53 ` Santosh Y
2013-05-08 8:43 ` Seungwon Jeon [this message]
2013-05-09 6:53 ` [PATCH v4 6/6] scsi: ufs: add dme control primitives Santosh Y
2013-05-10 10:42 ` [PATCH] scsi: ufs: use devres functions for ufshcd Seungwon Jeon
2013-05-10 11:00 ` Seungwon Jeon
2013-05-10 11:05 ` [PATCH resend] " Seungwon Jeon
2013-05-02 7:27 ` [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU Santosh Y
2013-05-02 11:31 ` Sujit Reddy Thumma
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='002901ce4bc8$0bdb58f0$23920ad0$%jun@samsung.com' \
--to=tgih.jun@samsung.com \
--cc=JBottomley@parallels.com \
--cc=linux-scsi@vger.kernel.org \
--cc=santoshsy@gmail.com \
--cc=vinholikatti@gmail.com \
/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