* [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU
@ 2013-04-24 14:14 Sujit Reddy Thumma
2013-04-24 16:06 ` [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c Seungwon Jeon
2013-05-02 7:27 ` [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU Santosh Y
0 siblings, 2 replies; 52+ messages in thread
From: Sujit Reddy Thumma @ 2013-04-24 14:14 UTC (permalink / raw)
To: Vinayak Holikatti, Santosh Y, James E.J. Bottomley
Cc: Sujit Reddy Thumma, linux-arm-msm, linux-scsi, linux-kernel
As part of device initialization sequence, sending NOP OUT UPIU and
waiting for NOP IN UPIU response is mandatory. This confirms that the
device UFS Transport (UTP) layer is functional and the host can configure
the device with further commands. Add support for sending NOP OUT UPIU to
check the device connection path and test whether the UTP layer on the
device side is functional during initialization.
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 167 ++++++++++++++++++++++++++++++++++++++++++---
drivers/scsi/ufs/ufshcd.h | 4 +
2 files changed, 162 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ced421a..1a8cba3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -34,12 +34,21 @@
*/
#include "ufshcd.h"
+#include <linux/iopoll.h>
+#include <linux/async.h>
/* Timeout after 10 secs if UIC command hangs */
#define UIC_COMMAND_TIMEOUT (10 * HZ)
/* Retry for 3 times in case of UIC failures */
#define UIC_COMMAND_RETRIES 3
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES 10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT 30 /* msecs */
+/* Reserved tag for internal commands */
+#define INTERNAL_CMD_TAG 0
+
enum {
UFSHCD_MAX_CHANNEL = 0,
UFSHCD_MAX_ID = 1,
@@ -607,7 +616,7 @@ static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags)
{
struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
enum dma_data_direction cmd_dir =
- lrbp->cmd->sc_data_direction;
+ lrbp->cmd ? lrbp->cmd->sc_data_direction : DMA_NONE;
u32 data_direction;
u32 dword_0;
@@ -624,6 +633,8 @@ static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags)
dword_0 = data_direction | (lrbp->command_type
<< UPIU_COMMAND_TYPE_OFFSET);
+ if (lrbp->intr_cmd)
+ dword_0 |= UTP_REQ_DESC_INT_CMD;
/* Transfer request descriptor header fields */
req_desc->header.dword_0 = cpu_to_le32(dword_0);
@@ -712,6 +723,18 @@ static inline void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
}
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
+{
+ struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+ memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+ /* command descriptor fields */
+ ucd_req_ptr->header.dword_0 =
+ UPIU_HEADER_DWORD(
+ UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+}
+
/**
* ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
* @hba - UFS hba
@@ -741,12 +764,14 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
case UTP_CMD_TYPE_SCSI:
case UTP_CMD_TYPE_DEV_MANAGE:
ufshcd_prepare_req_desc(lrbp, &upiu_flags);
- if (lrbp->cmd && lrbp->command_type == UTP_CMD_TYPE_SCSI)
+ if (lrbp->cmd && lrbp->command_type == UTP_CMD_TYPE_SCSI) {
ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
- else if (lrbp->cmd)
+ } else if (lrbp->cmd && ufshcd_is_query_req(lrbp)) {
ufshcd_prepare_utp_query_req_upiu(hba, lrbp,
upiu_flags);
- else {
+ } else if (!lrbp->cmd) {
+ ufshcd_prepare_utp_nop_upiu(lrbp);
+ } else {
dev_err(hba->dev, "%s: Invalid UPIU request\n",
__func__);
ret = -EINVAL;
@@ -799,6 +824,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
lrbp->sense_buffer = cmd->sense_buffer;
lrbp->task_tag = tag;
lrbp->lun = cmd->device->lun;
+ lrbp->intr_cmd = false;
if (ufshcd_is_query_req(lrbp))
lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
@@ -1112,6 +1138,113 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
return err;
}
+static inline int
+ufshcd_compose_nop_out_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+ lrbp->cmd = NULL;
+ lrbp->sense_bufflen = 0;
+ lrbp->sense_buffer = NULL;
+ lrbp->task_tag = INTERNAL_CMD_TAG;
+ lrbp->lun = 0; /* NOP OUT is not specific to any LUN */
+ lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+ lrbp->intr_cmd = true; /* No interrupt aggregation */
+
+ return ufshcd_compose_upiu(hba, lrbp);
+}
+
+/**
+ * ufshcd_validate_dev_connection() - Check device connection status
+ * @hba: per-adapter instance
+ *
+ * Send NOP OUT UPIU and wait for NOP IN response to check whether the
+ * device Transport Protocol (UTP) layer is ready after a reset.
+ * If the UTP layer at the device side is not initialized, it may
+ * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
+ * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
+ */
+static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
+{
+ int err;
+ struct ufshcd_lrb *lrbp;
+ unsigned long timeout;
+ unsigned long flags;
+ struct completion wait;
+ int retries = NOP_OUT_RETRIES;
+
+retry:
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ lrbp = &hba->lrb[INTERNAL_CMD_TAG];
+ init_completion(&wait);
+
+ err = ufshcd_compose_nop_out_upiu(hba, lrbp);
+ if (err)
+ goto may_retry;
+
+ lrbp->completion = &wait;
+ ufshcd_send_command(hba, INTERNAL_CMD_TAG);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ timeout = wait_for_completion_timeout(
+ &wait, msecs_to_jiffies(NOP_OUT_TIMEOUT));
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (timeout > 0) {
+ int ocs;
+
+ ocs = ufshcd_get_tr_ocs(lrbp);
+ switch (ocs) {
+ case OCS_SUCCESS:
+ goto out;
+ default:
+ dev_dbg(hba->dev, "%s: OCS error %d\n", __func__, ocs);
+ err = -EIO;
+ goto may_retry;
+ }
+ } else {
+ u32 reg;
+
+ err = -ETIMEDOUT;
+
+ /* clear outstanding transaction before retry */
+ ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
+ __clear_bit(INTERNAL_CMD_TAG, &hba->outstanding_reqs);
+
+ /* poll for max. 1 sec to clear door bell register by h/w */
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (readl_poll_timeout(
+ hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL,
+ reg, !(reg & INTERNAL_CMD_TAG), 1000, 1000))
+ retries = 0;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ goto may_retry;
+ }
+
+may_retry:
+ if (retries--) {
+ dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ goto retry;
+ }
+
+out:
+ if (err)
+ dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return err;
+}
+
+static void ufshcd_async_device_probe(void *data, async_cookie_t cookie)
+{
+ int err;
+ struct ufs_hba *hba = data;
+
+ err = ufshcd_validate_dev_connection(hba);
+ if (err)
+ dev_err(hba->dev, "%s failed with error %d\n", __func__, err);
+ else
+ scsi_scan_host(hba->host);
+}
+
/**
* ufshcd_make_hba_operational - Make UFS controller operational
* @hba: per adapter instance
@@ -1166,7 +1299,6 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
scsi_unblock_requests(hba->host);
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
- scsi_scan_host(hba->host);
out:
return err;
}
@@ -1568,6 +1700,16 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
}
/**
+ * ufshcd_is_nop_out_upiu() - check if the command is NOP OUT UPIU
+ * @lrbp: pointer to logical reference block
+ */
+static inline bool ufshcd_is_nop_out_upiu(struct ufshcd_lrb *lrbp)
+{
+ return (be32_to_cpu(lrbp->ucd_req_ptr->header.dword_0) >> 24) ==
+ UPIU_TRANSACTION_NOP_OUT;
+}
+
+/**
* ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
*/
@@ -1578,6 +1720,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
u32 tr_doorbell;
int result;
int index;
+ bool int_aggr_reset = true;
lrb = hba->lrb;
tr_doorbell =
@@ -1586,17 +1729,20 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
for (index = 0; index < hba->nutrs; index++) {
if (test_bit(index, &completed_reqs)) {
-
- result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
-
if (lrb[index].cmd) {
+ result = ufshcd_transfer_rsp_status(
+ hba, &lrb[index]);
scsi_dma_unmap(lrb[index].cmd);
lrb[index].cmd->result = result;
lrb[index].cmd->scsi_done(lrb[index].cmd);
/* Mark completed command as NULL in LRB */
lrb[index].cmd = NULL;
+ } else if (ufshcd_is_nop_out_upiu(&lrb[index])) {
+ complete(lrb[index].completion);
}
+ /* Don't reset counters for interrupt cmd */
+ int_aggr_reset = lrb[index].intr_cmd ? false : true;
} /* end of if */
} /* end of for */
@@ -1604,7 +1750,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
hba->outstanding_reqs ^= completed_reqs;
/* Reset interrupt aggregation counters */
- ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+ if (int_aggr_reset)
+ ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
}
/**
@@ -2098,6 +2245,8 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
dev_err(hba->dev, "Initialization failed\n");
goto out_remove_scsi_host;
}
+
+ async_schedule(ufshcd_async_device_probe, hba);
*hba_handle = hba;
return 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 13378f3..e273bf7 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -101,6 +101,8 @@ struct uic_command {
* @command_type: SCSI, UFS, Query.
* @task_tag: Task tag of the command
* @lun: LUN of the command
+ * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
+ * @completion: holds the state of completion (used for internal commands)
*/
struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
@@ -116,6 +118,8 @@ struct ufshcd_lrb {
int command_type;
int task_tag;
unsigned int lun;
+ bool intr_cmd;
+ struct completion *completion;
};
/**
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation.
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
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 ` Seungwon Jeon
2013-04-30 11:17 ` Subhash Jadavani
` (2 more replies)
2013-05-02 7:27 ` [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU Santosh Y
1 sibling, 3 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-04-24 16:06 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Move the ufshcd_hba_stop from header file.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
drivers/scsi/ufs/ufshcd.c | 9 +++++++++
drivers/scsi/ufs/ufshcd.h | 9 ---------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 60fd40c..41b9639 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
}
/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+ writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
* ufshcd_is_hba_active - Get controller state
* @hba: per adapter instance
*
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6b99a42..1680394 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
-/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
- writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
-}
-
#endif /* End of Header */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
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-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
2 siblings, 1 reply; 52+ messages in thread
From: Subhash Jadavani @ 2013-04-30 11:17 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Looks good. Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
> Move the ufshcd_hba_stop from header file.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> drivers/scsi/ufs/ufshcd.c | 9 +++++++++
> drivers/scsi/ufs/ufshcd.h | 9 ---------
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 60fd40c..41b9639 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> }
>
> /**
> + * ufshcd_hba_stop - Send controller to reset state
> + * @hba: per adapter instance
> + */
> +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> +{
> + writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> +}
> +
> +/**
> * ufshcd_is_hba_active - Get controller state
> * @hba: per adapter instance
> *
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 6b99a42..1680394 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
>
> -/**
> - * ufshcd_hba_stop - Send controller to reset state
> - * @hba: per adapter instance
> - */
> -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> -{
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> -}
> -
> #endif /* End of Header */
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
2013-04-30 11:17 ` Subhash Jadavani
@ 2013-05-01 7:46 ` merez
0 siblings, 0 replies; 52+ messages in thread
From: merez @ 2013-05-01 7:46 UTC (permalink / raw)
To: Subhash Jadavani
Cc: Seungwon Jeon, linux-scsi, 'Vinayak Holikatti',
'Santosh Y', 'James E.J. Bottomley'
Tested-by: Maya Erez <merez@codeaurora.org>
>
> Looks good. Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
>
> On 4/24/2013 9:36 PM, Seungwon Jeon wrote:
>> Move the ufshcd_hba_stop from header file.
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> ---
>> drivers/scsi/ufs/ufshcd.c | 9 +++++++++
>> drivers/scsi/ufs/ufshcd.h | 9 ---------
>> 2 files changed, 9 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> index 60fd40c..41b9639 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba
>> *hba)
>> }
>>
>> /**
>> + * ufshcd_hba_stop - Send controller to reset state
>> + * @hba: per adapter instance
>> + */
>> +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
>> +{
>> + writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
>> +}
>> +
>> +/**
>> * ufshcd_is_hba_active - Get controller state
>> * @hba: per adapter instance
>> *
>> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
>> index 6b99a42..1680394 100644
>> --- a/drivers/scsi/ufs/ufshcd.h
>> +++ b/drivers/scsi/ufs/ufshcd.h
>> @@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba **
>> , void __iomem * ,
>> unsigned int);
>> void ufshcd_remove(struct ufs_hba *);
>>
>> -/**
>> - * ufshcd_hba_stop - Send controller to reset state
>> - * @hba: per adapter instance
>> - */
>> -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
>> -{
>> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
>> -}
>> -
>> #endif /* End of Header */
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU
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-05-02 7:27 ` Santosh Y
2013-05-02 11:31 ` Sujit Reddy Thumma
1 sibling, 1 reply; 52+ messages in thread
From: Santosh Y @ 2013-05-02 7:27 UTC (permalink / raw)
To: Sujit Reddy Thumma
Cc: Vinayak Holikatti, James E.J. Bottomley, linux-arm-msm,
linux-scsi, linux-kernel
> +
> +/**
> + * ufshcd_validate_dev_connection() - Check device connection status
> + * @hba: per-adapter instance
> + *
> + * Send NOP OUT UPIU and wait for NOP IN response to check whether the
> + * device Transport Protocol (UTP) layer is ready after a reset.
> + * If the UTP layer at the device side is not initialized, it may
> + * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
> + * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
> + */
> +static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
> +{
> + int err;
> + struct ufshcd_lrb *lrbp;
> + unsigned long timeout;
> + unsigned long flags;
> + struct completion wait;
> + int retries = NOP_OUT_RETRIES;
> +
> +retry:
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + lrbp = &hba->lrb[INTERNAL_CMD_TAG];
> + init_completion(&wait);
> +
> + err = ufshcd_compose_nop_out_upiu(hba, lrbp);
> + if (err)
> + goto may_retry;
> +
> + lrbp->completion = &wait;
> + ufshcd_send_command(hba, INTERNAL_CMD_TAG);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + timeout = wait_for_completion_timeout(
> + &wait, msecs_to_jiffies(NOP_OUT_TIMEOUT));
> +
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + if (timeout > 0) {
> + int ocs;
> +
> + ocs = ufshcd_get_tr_ocs(lrbp);
> + switch (ocs) {
> + case OCS_SUCCESS:
> + goto out;
> + default:
> + dev_dbg(hba->dev, "%s: OCS error %d\n", __func__, ocs);
> + err = -EIO;
> + goto may_retry;
> + }
> + } else {
> + u32 reg;
> +
> + err = -ETIMEDOUT;
> +
> + /* clear outstanding transaction before retry */
> + ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
> + __clear_bit(INTERNAL_CMD_TAG, &hba->outstanding_reqs);
> +
> + /* poll for max. 1 sec to clear door bell register by h/w */
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> + if (readl_poll_timeout(
> + hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL,
> + reg, !(reg & INTERNAL_CMD_TAG), 1000, 1000))
Condition is always true here, change it to !(reg & (1 << INTERNAL_CMD_TAG)).
> + retries = 0;
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + goto may_retry;
> + }
> +
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
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-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
2 siblings, 2 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-02 8:11 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Wed, Apr 24, 2013 at 9:36 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Move the ufshcd_hba_stop from header file.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> drivers/scsi/ufs/ufshcd.c | 9 +++++++++
> drivers/scsi/ufs/ufshcd.h | 9 ---------
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 60fd40c..41b9639 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> }
>
> /**
> + * ufshcd_hba_stop - Send controller to reset state
> + * @hba: per adapter instance
> + */
> +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> +{
> + writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> +}
> +
> +/**
> * ufshcd_is_hba_active - Get controller state
> * @hba: per adapter instance
> *
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 6b99a42..1680394 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
>
> -/**
> - * ufshcd_hba_stop - Send controller to reset state
> - * @hba: per adapter instance
> - */
> -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> -{
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> -}
> -
> #endif /* End of Header */
> --
> 1.7.0.4
>
>
The patch doesn't apply due to the character set.
"fatal: cannot convert from ks_c_5601-1987 to UTF-8"
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 1/1] scsi: ufs: Add support for sending NOP OUT UPIU
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
0 siblings, 0 replies; 52+ messages in thread
From: Sujit Reddy Thumma @ 2013-05-02 11:31 UTC (permalink / raw)
To: Santosh Y
Cc: Vinayak Holikatti, James E.J. Bottomley, linux-arm-msm,
linux-scsi, linux-kernel
On 5/2/2013 12:57 PM, Santosh Y wrote:
>> +
>> +/**
>> + * ufshcd_validate_dev_connection() - Check device connection status
>> + * @hba: per-adapter instance
>> + *
>> + * Send NOP OUT UPIU and wait for NOP IN response to check whether the
>> + * device Transport Protocol (UTP) layer is ready after a reset.
>> + * If the UTP layer at the device side is not initialized, it may
>> + * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
>> + * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
>> + */
>> +static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
>> +{
>> + int err;
>> + struct ufshcd_lrb *lrbp;
>> + unsigned long timeout;
>> + unsigned long flags;
>> + struct completion wait;
>> + int retries = NOP_OUT_RETRIES;
>> +
>> +retry:
>> + spin_lock_irqsave(hba->host->host_lock, flags);
>> + lrbp = &hba->lrb[INTERNAL_CMD_TAG];
>> + init_completion(&wait);
>> +
>> + err = ufshcd_compose_nop_out_upiu(hba, lrbp);
>> + if (err)
>> + goto may_retry;
>> +
>> + lrbp->completion = &wait;
>> + ufshcd_send_command(hba, INTERNAL_CMD_TAG);
>> + spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> + timeout = wait_for_completion_timeout(
>> + &wait, msecs_to_jiffies(NOP_OUT_TIMEOUT));
>> +
>> + spin_lock_irqsave(hba->host->host_lock, flags);
>> + if (timeout > 0) {
>> + int ocs;
>> +
>> + ocs = ufshcd_get_tr_ocs(lrbp);
>> + switch (ocs) {
>> + case OCS_SUCCESS:
>> + goto out;
>> + default:
>> + dev_dbg(hba->dev, "%s: OCS error %d\n", __func__, ocs);
>> + err = -EIO;
>> + goto may_retry;
>> + }
>> + } else {
>> + u32 reg;
>> +
>> + err = -ETIMEDOUT;
>> +
>> + /* clear outstanding transaction before retry */
>> + ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
>> + __clear_bit(INTERNAL_CMD_TAG, &hba->outstanding_reqs);
>> +
>> + /* poll for max. 1 sec to clear door bell register by h/w */
>> + spin_unlock_irqrestore(hba->host->host_lock, flags);
>> + if (readl_poll_timeout(
>> + hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL,
>> + reg, !(reg & INTERNAL_CMD_TAG), 1000, 1000))
>
> Condition is always true here, change it to !(reg & (1 << INTERNAL_CMD_TAG)).
Good catch. I will update.
>
>> + retries = 0;
>> + spin_lock_irqsave(hba->host->host_lock, flags);
>> + goto may_retry;
>> + }
>> +
>
>
>
--
Regards,
Sujit
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
2013-05-02 8:11 ` Santosh Y
@ 2013-05-02 13:37 ` Seungwon Jeon
2013-05-02 18:49 ` merez
1 sibling, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-02 13:37 UTC (permalink / raw)
To: 'Santosh Y'
Cc: linux-scsi, 'Vinayak Holikatti',
'James E.J. Bottomley'
On Thursday, May 02, 2013, Santosh Y wrote:
> On Wed, Apr 24, 2013 at 9:36 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Move the ufshcd_hba_stop from header file.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > ---
> > drivers/scsi/ufs/ufshcd.c | 9 +++++++++
> > drivers/scsi/ufs/ufshcd.h | 9 ---------
> > 2 files changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index 60fd40c..41b9639 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> > }
> >
> > /**
> > + * ufshcd_hba_stop - Send controller to reset state
> > + * @hba: per adapter instance
> > + */
> > +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > +{
> > + writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > +}
> > +
> > +/**
> > * ufshcd_is_hba_active - Get controller state
> > * @hba: per adapter instance
> > *
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index 6b99a42..1680394 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> > unsigned int);
> > void ufshcd_remove(struct ufs_hba *);
> >
> > -/**
> > - * ufshcd_hba_stop - Send controller to reset state
> > - * @hba: per adapter instance
> > - */
> > -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > -{
> > - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > -}
> > -
> > #endif /* End of Header */
> > --
> > 1.7.0.4
> >
> >
>
> The patch doesn't apply due to the character set.
>
> "fatal: cannot convert from ks_c_5601-1987 to UTF-8"
Oh, I didn't see the problem.
I'll check more for resend.
Thanks,
Seungwon Jeon
>
>
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
2013-05-02 8:11 ` Santosh Y
2013-05-02 13:37 ` Seungwon Jeon
@ 2013-05-02 18:49 ` merez
1 sibling, 0 replies; 52+ messages in thread
From: merez @ 2013-05-02 18:49 UTC (permalink / raw)
To: Santosh Y
Cc: Seungwon Jeon, linux-scsi, Vinayak Holikatti,
James E.J. Bottomley
Hi,
Can you please rebase the next version on top of the following patches
which are the next candidates for merge?
Vinayak Holikatti (2):
ufs: Add Platform glue driver for ufshcd
ufs: Correct the expected data transfersize
Dolev Raviv (1):
scsi: ufs: add support for query requests
Thanks,
Maya
> On Wed, Apr 24, 2013 at 9:36 PM, Seungwon Jeon <tgih.jun@samsung.com>
> wrote:
>> Move the ufshcd_hba_stop from header file.
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> ---
>> drivers/scsi/ufs/ufshcd.c | 9 +++++++++
>> drivers/scsi/ufs/ufshcd.h | 9 ---------
>> 2 files changed, 9 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> index 60fd40c..41b9639 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -285,6 +285,15 @@ static inline void ufshcd_hba_start(struct ufs_hba
>> *hba)
>> }
>>
>> /**
>> + * ufshcd_hba_stop - Send controller to reset state
>> + * @hba: per adapter instance
>> + */
>> +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
>> +{
>> + writel(CONTROLLER_DISABLE, (hba->mmio_base +
>> REG_CONTROLLER_ENABLE));
>> +}
>> +
>> +/**
>> * ufshcd_is_hba_active - Get controller state
>> * @hba: per adapter instance
>> *
>> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
>> index 6b99a42..1680394 100644
>> --- a/drivers/scsi/ufs/ufshcd.h
>> +++ b/drivers/scsi/ufs/ufshcd.h
>> @@ -190,13 +190,4 @@ int ufshcd_init(struct device *, struct ufs_hba **
>> , void __iomem * ,
>> unsigned int);
>> void ufshcd_remove(struct ufs_hba *);
>>
>> -/**
>> - * ufshcd_hba_stop - Send controller to reset state
>> - * @hba: per adapter instance
>> - */
>> -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
>> -{
>> - writel(CONTROLLER_DISABLE, (hba->mmio_base +
>> REG_CONTROLLER_ENABLE));
>> -}
>> -
>> #endif /* End of Header */
>> --
>> 1.7.0.4
>>
>>
>
> The patch doesn't apply due to the character set.
>
> "fatal: cannot convert from ks_c_5601-1987 to UTF-8"
>
>
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
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-02 8:11 ` Santosh Y
@ 2013-05-04 8:45 ` Seungwon Jeon
2013-05-05 11:22 ` merez
` (13 more replies)
2 siblings, 14 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-04 8:45 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Move the ufshcd_hba_stop from header file.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
Tested-by: Maya Erez <merez@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 9 +++++++++
drivers/scsi/ufs/ufshcd.h | 9 ---------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f244812..d932239 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -280,6 +280,15 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
}
/**
+ * ufshcd_hba_stop - Send controller to reset state
+ * @hba: per adapter instance
+ */
+static inline void ufshcd_hba_stop(struct ufs_hba *hba)
+{
+ writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+}
+
+/**
* ufshcd_is_hba_active - Get controller state
* @hba: per adapter instance
*
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 336980b..3a1052d 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -208,13 +208,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
-/**
- * ufshcd_hba_stop - Send controller to reset state
- * @hba: per adapter instance
- */
-static inline void ufshcd_hba_stop(struct ufs_hba *hba)
-{
- writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
-}
-
#endif /* End of Header */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
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
` (12 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: merez @ 2013-05-05 11:22 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Hi,
ufshcd_pci_shutdown (in ufshcd_pci.c) is using ufshcd_hba_stop so it
cannot be moved to ufshcd.c.
Sorry for missing it last time I tested, I returned ufshcd_hba_stop to
ufshcd.h by mistake when I resolved conflicts of the next patch so I
didn't hit the compilation errors.
Thanks,
Maya
> Move the ufshcd_hba_stop from header file.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 9 +++++++++
> drivers/scsi/ufs/ufshcd.h | 9 ---------
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index f244812..d932239 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -280,6 +280,15 @@ static inline void ufshcd_hba_start(struct ufs_hba
> *hba)
> }
>
> /**
> + * ufshcd_hba_stop - Send controller to reset state
> + * @hba: per adapter instance
> + */
> +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> +{
> + writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> +}
> +
> +/**
> * ufshcd_is_hba_active - Get controller state
> * @hba: per adapter instance
> *
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 336980b..3a1052d 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -208,13 +208,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** ,
> void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
>
> -/**
> - * ufshcd_hba_stop - Send controller to reset state
> - * @hba: per adapter instance
> - */
> -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> -{
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> -}
> -
> #endif /* End of Header */
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c
2013-05-05 11:22 ` merez
@ 2013-05-06 3:05 ` Seungwon Jeon
0 siblings, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 3:05 UTC (permalink / raw)
To: merez
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
On Sunday, May 05, 2013 8:23, Merze wrote:
> Hi,
>
> ufshcd_pci_shutdown (in ufshcd_pci.c) is using ufshcd_hba_stop so it
> cannot be moved to ufshcd.c.
> Sorry for missing it last time I tested, I returned ufshcd_hba_stop to
> ufshcd.h by mistake when I resolved conflicts of the next patch so I
> didn't hit the compilation errors.
Oh, I also missed this. Thank you for informing.
I'll keep ufshcd_hba_stop function in place and
just touch for the patch of "scsi: ufs: wrap the i/o access operations".
Thanks,
Seungwon Jeon
>
> Thanks,
> Maya
> > Move the ufshcd_hba_stop from header file.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
> > Tested-by: Maya Erez <merez@codeaurora.org>
> > ---
> > drivers/scsi/ufs/ufshcd.c | 9 +++++++++
> > drivers/scsi/ufs/ufshcd.h | 9 ---------
> > 2 files changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index f244812..d932239 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -280,6 +280,15 @@ static inline void ufshcd_hba_start(struct ufs_hba
> > *hba)
> > }
> >
> > /**
> > + * ufshcd_hba_stop - Send controller to reset state
> > + * @hba: per adapter instance
> > + */
> > +static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > +{
> > + writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > +}
> > +
> > +/**
> > * ufshcd_is_hba_active - Get controller state
> > * @hba: per adapter instance
> > *
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index 336980b..3a1052d 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -208,13 +208,4 @@ int ufshcd_init(struct device *, struct ufs_hba ** ,
> > void __iomem * ,
> > unsigned int);
> > void ufshcd_remove(struct ufs_hba *);
> >
> > -/**
> > - * ufshcd_hba_stop - Send controller to reset state
> > - * @hba: per adapter instance
> > - */
> > -static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > -{
> > - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > -}
> > -
> > #endif /* End of Header */
> > --
> > 1.7.0.4
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
>
>
> --
> Maya Erez
> 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-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
2013-05-05 11:22 ` merez
@ 2013-05-06 5:37 ` Seungwon Jeon
2013-05-06 10:37 ` merez
2013-05-06 19:30 ` Santosh Y
2013-05-06 5:37 ` [PATCH v3 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
` (11 subsequent siblings)
13 siblings, 2 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 5:37 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Simplify operations with hiding mmio_base.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 105 +++++++++++++++++++--------------------------
drivers/scsi/ufs/ufshcd.h | 7 +++-
2 files changed, 50 insertions(+), 62 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f244812..cf7c8e4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,7 +71,7 @@ enum {
*/
static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
{
- return readl(hba->mmio_base + REG_UFS_VERSION);
+ return ufshcd_readl(hba, REG_UFS_VERSION);
}
/**
@@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
*/
static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
{
- writel(~(1 << pos),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+ ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
}
/**
@@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
*/
static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
{
- return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
MASK_UIC_COMMAND_RESULT;
}
@@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
{
switch (option) {
case INT_AGGR_RESET:
- writel((INT_AGGR_ENABLE |
- INT_AGGR_COUNTER_AND_TIMER_RESET),
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
case INT_AGGR_CONFIG:
- writel((INT_AGGR_ENABLE |
- INT_AGGR_PARAM_WRITE |
- INT_AGGR_COUNTER_THRESHOLD_VALUE |
- INT_AGGR_TIMEOUT_VALUE),
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
}
}
@@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
*/
static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
{
- writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
- (hba->mmio_base +
- REG_UTP_TASK_REQ_LIST_RUN_STOP));
- writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+ ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+ ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
}
/**
@@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
*/
static inline void ufshcd_hba_start(struct ufs_hba *hba)
{
- writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+ ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
}
/**
@@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
*/
static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
{
- return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+ return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
}
/**
@@ -299,8 +293,7 @@ static inline
void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
{
__set_bit(task_tag, &hba->outstanding_reqs);
- writel((1 << task_tag),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+ ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
}
/**
@@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
*/
static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
{
- hba->capabilities =
- readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -399,16 +391,13 @@ static inline void
ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
{
/* Write Args */
- writel(uic_cmnd->argument1,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
- writel(uic_cmnd->argument2,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
- writel(uic_cmnd->argument3,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
+ ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
/* Write UIC Cmd */
- writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
- (hba->mmio_base + REG_UIC_COMMAND));
+ ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+ REG_UIC_COMMAND);
}
/**
@@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
{
switch (option) {
case UFSHCD_INT_ENABLE:
- writel(hba->int_enable_mask,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
break;
case UFSHCD_INT_DISABLE:
if (hba->ufs_version == UFSHCI_VERSION_10)
- writel(INTERRUPT_DISABLE_MASK_10,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
+ REG_INTERRUPT_ENABLE);
else
- writel(INTERRUPT_DISABLE_MASK_11,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
+ REG_INTERRUPT_ENABLE);
break;
}
}
@@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
unsigned long flags;
/* check if controller is ready to accept UIC commands */
- if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
+ if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
UIC_COMMAND_READY) == 0x0) {
dev_err(hba->dev,
"Controller not ready"
@@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
u32 reg;
/* check if device present */
- reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
+ reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
if (!ufshcd_is_device_present(reg)) {
dev_err(hba->dev, "cc: Device not present\n");
err = -ENXIO;
@@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
return -EIO;
/* Configure UTRL and UTMRL base address registers */
- writel(lower_32_bits(hba->utrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
- writel(upper_32_bits(hba->utrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
- writel(lower_32_bits(hba->utmrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
- writel(upper_32_bits(hba->utmrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
+ ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
/* Initialize unipro link startup procedure */
return ufshcd_dme_link_startup(hba);
@@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
int index;
lrb = hba->lrb;
- tr_doorbell =
- readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
for (index = 0; index < hba->nutrs; index++) {
@@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
goto fatal_eh;
if (hba->errors & UIC_ERROR) {
-
- reg = readl(hba->mmio_base +
- REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
goto fatal_eh;
}
@@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
{
u32 tm_doorbell;
- tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
+ tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
}
@@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
struct ufs_hba *hba = __hba;
spin_lock(hba->host->host_lock);
- intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
if (intr_status) {
ufshcd_sl_intr(hba, intr_status);
/* If UFSHCI 1.0 then clear interrupt status register */
if (hba->ufs_version == UFSHCI_VERSION_10)
- writel(intr_status,
- (hba->mmio_base + REG_INTERRUPT_STATUS));
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
@@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
/* send command to the controller */
__set_bit(free_slot, &hba->outstanding_tasks);
- writel((1 << free_slot),
- (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
+ ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
spin_unlock_irqrestore(host->host_lock, flags);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 336980b..6429bed 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -204,6 +204,11 @@ struct ufs_hba {
struct ufs_query query;
};
+#define ufshcd_writel(hba, val, reg) \
+ writel((val), (hba)->mmio_base + (reg))
+#define ufshcd_readl(hba, reg) \
+ readl((hba)->mmio_base + (reg))
+
int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
@@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
*/
static inline void ufshcd_hba_stop(struct ufs_hba *hba)
{
- writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+ ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
}
#endif /* End of Header */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v3 2/6] scsi: ufs: amend interrupt configuration
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
2013-05-05 11:22 ` merez
2013-05-06 5:37 ` [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations Seungwon Jeon
@ 2013-05-06 5:37 ` 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
` (10 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 5:37 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
It makes interrupt setting more flexible especially
for disabling. And wrong bit mask is fixed for ver 1.0.
[17:16] is added for mask.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 84 +++++++++++++++++++++++++++++++-------------
drivers/scsi/ufs/ufshcd.h | 4 +-
drivers/scsi/ufs/ufshci.h | 5 ++-
3 files changed, 64 insertions(+), 29 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index cf7c8e4..feaf221 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -35,6 +35,10 @@
#include "ufshcd.h"
+#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
+ UTP_TASK_REQ_COMPL |\
+ UFSHCD_ERROR_MASK)
+
enum {
UFSHCD_MAX_CHANNEL = 0,
UFSHCD_MAX_ID = 1,
@@ -64,6 +68,20 @@ enum {
};
/**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+ if (hba->ufs_version == UFSHCI_VERSION_10)
+ return INTERRUPT_MASK_ALL_VER_10;
+ else
+ return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
* ufshcd_get_ufs_version - Get the UFS version supported by the HBA
* @hba - Pointer to adapter instance
*
@@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
}
/**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
* @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
*/
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
{
- switch (option) {
- case UFSHCD_INT_ENABLE:
- ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
- break;
- case UFSHCD_INT_DISABLE:
- if (hba->ufs_version == UFSHCI_VERSION_10)
- ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
- REG_INTERRUPT_ENABLE);
- else
- ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
- REG_INTERRUPT_ENABLE);
- break;
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+ if (hba->ufs_version == UFSHCI_VERSION_10) {
+ u32 rw;
+ rw = set & INTERRUPT_MASK_RW_VER_10;
+ set = rw | ((set ^ intrs) & intrs);
+ } else {
+ set |= intrs;
+ }
+
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+}
+
+/**
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
+ */
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
+{
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+ if (hba->ufs_version == UFSHCI_VERSION_10) {
+ u32 rw;
+ rw = (set & INTERRUPT_MASK_RW_VER_10) &
+ ~(intrs & INTERRUPT_MASK_RW_VER_10);
+ set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
+
+ } else {
+ set &= ~intrs;
}
+
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
}
/**
@@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument3 = 0;
/* enable UIC related interrupts */
- hba->int_enable_mask |= UIC_COMMAND_COMPL;
- ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
/* sending UIC commands to controller */
ufshcd_send_uic_command(hba, uic_cmd);
@@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
}
/* Enable required interrupts */
- hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
- UIC_ERROR |
- UTP_TASK_REQ_COMPL |
- DEVICE_FATAL_ERROR |
- CONTROLLER_FATAL_ERROR |
- SYSTEM_BUS_FATAL_ERROR);
- ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
/* Configure interrupt aggregation */
ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
@@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
void ufshcd_remove(struct ufs_hba *hba)
{
/* disable interrupts */
- ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+ ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_version(hba);
+ /* Get Interrupt bit mask per version */
+ hba->intr_mask = ufshcd_get_intr_mask(hba);
+
/* Allocate memory for host memory space */
err = ufshcd_memory_alloc(hba);
if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6429bed..d98e046 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -153,7 +153,7 @@ struct ufs_query {
* @ufshcd_tm_wait_queue: wait queue for task management
* @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
- * @int_enable_mask: Interrupt Mask Bits
+ * @intr_mask: Interrupt Mask Bits
* @uic_workq: Work queue for UIC completion handling
* @feh_workq: Work queue for fatal controller error handling
* @errors: HBA errors
@@ -191,7 +191,7 @@ struct ufs_hba {
unsigned long tm_condition;
u32 ufshcd_state;
- u32 int_enable_mask;
+ u32 intr_mask;
/* Work Queues */
struct work_struct uic_workq;
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 4a86247..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -232,10 +232,11 @@ enum {
/* Interrupt disable masks */
enum {
/* Interrupt disable mask for UFSHCI v1.0 */
- INTERRUPT_DISABLE_MASK_10 = 0xFFFF,
+ INTERRUPT_MASK_ALL_VER_10 = 0x30FFF,
+ INTERRUPT_MASK_RW_VER_10 = 0x30000,
/* Interrupt disable mask for UFSHCI v1.1 */
- INTERRUPT_DISABLE_MASK_11 = 0x0,
+ INTERRUPT_MASK_ALL_VER_11 = 0x31FFF,
};
/*
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v3 3/6] scsi: ufs: fix interrupt status clears
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (2 preceding siblings ...)
2013-05-06 5:37 ` [PATCH v3 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
@ 2013-05-06 5:37 ` 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
` (9 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 5:37 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
drivers/scsi/ufs/ufshcd.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index feaf221..e04c74e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1582,11 +1582,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
if (intr_status) {
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
ufshcd_sl_intr(hba, intr_status);
-
- /* If UFSHCI 1.0 then clear interrupt status register */
- if (hba->ufs_version == UFSHCI_VERSION_10)
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v3 4/6] scsi: ufs: rework link start-up process
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (3 preceding siblings ...)
2013-05-06 5:37 ` [PATCH v3 3/6] scsi: ufs: fix interrupt status clears Seungwon Jeon
@ 2013-05-06 5:37 ` Seungwon Jeon
2013-05-06 9:47 ` Sujit Reddy Thumma
2013-05-06 5:37 ` [PATCH v3 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
` (8 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 5:37 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Link start-up requires long time with multiphase handshakes
between UFS host and device. This affects driver's probe time.
This patch let link start-up run asynchronously. Link start-up
will be executed at the end of prove separately.
Along with this change, the following is worked.
Defined completion time of uic command to avoid a permanent wait.
Added mutex to guarantee of uic command at a time.
Adapted some sequence of controller initialization after link statup
according to HCI standard.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 287 ++++++++++++++++++++++++++++++---------------
drivers/scsi/ufs/ufshcd.h | 10 +-
2 files changed, 200 insertions(+), 97 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e04c74e..118f104 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -33,11 +33,15 @@
* this program.
*/
+#include <linux/async.h>
+
#include "ufshcd.h"
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
UTP_TASK_REQ_COMPL |\
UFSHCD_ERROR_MASK)
+/* UIC command timeout, unit: ms */
+#define UIC_CMD_TIMEOUT 500
enum {
UFSHCD_MAX_CHANNEL = 0,
@@ -401,24 +405,115 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
}
/**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ * to accept UIC commands
* @hba: per adapter instance
- * @uic_command: UIC command
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+ if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Mutex must be held.
*/
static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
{
+ hba->active_uic_cmd = uic_cmd;
+
/* Write Args */
- ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
- ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
- ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
+ ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
/* Write UIC Cmd */
- ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+ ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
REG_UIC_COMMAND);
}
/**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Must be called with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+
+ if (wait_for_completion_timeout(&uic_cmd->done,
+ msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+ ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
+ else
+ ret = -ETIMEDOUT;
+
+ return ret;
+}
+
+/**
+ * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
+ * with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+ unsigned long flags;
+
+ if (!ufshcd_ready_for_uic_cmd(hba)) {
+ dev_err(hba->dev,
+ "Controller not ready to accept UIC commands\n");
+ return -EIO;
+ }
+
+ init_completion(&uic_cmd->done);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_dispatch_uic_cmd(hba, uic_cmd);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
+
+ return ret;
+}
+
+/**
+ * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+
+ mutex_lock(&hba->uic_cmd_mutex);
+ ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+ mutex_unlock(&hba->uic_cmd_mutex);
+
+ return ret;
+}
+
+/**
* ufshcd_map_sg - Map scatter-gather list to prdt
* @lrbp - pointer to local reference block
*
@@ -962,34 +1057,16 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
*/
static int ufshcd_dme_link_startup(struct ufs_hba *hba)
{
- struct uic_command *uic_cmd;
- unsigned long flags;
+ struct uic_command uic_cmd = {0};
+ int ret;
- /* check if controller is ready to accept UIC commands */
- if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
- UIC_COMMAND_READY) == 0x0) {
- dev_err(hba->dev,
- "Controller not ready"
- " to accept UIC commands\n");
- return -EIO;
- }
-
- spin_lock_irqsave(hba->host->host_lock, flags);
+ uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
- /* form UIC command */
- uic_cmd = &hba->active_uic_cmd;
- uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
- uic_cmd->argument1 = 0;
- uic_cmd->argument2 = 0;
- uic_cmd->argument3 = 0;
-
- /* enable UIC related interrupts */
- ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
-
- /* sending UIC commands to controller */
- ufshcd_send_uic_command(hba, uic_cmd);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- return 0;
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_err(hba->dev,
+ "link startup: error code %d\n", ret);
+ return ret;
}
/**
@@ -998,9 +1075,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
*
* To bring UFS host controller to operational state,
* 1. Check if device is present
- * 2. Configure run-stop-registers
- * 3. Enable required interrupts
- * 4. Configure interrupt aggregation
+ * 2. Enable required interrupts
+ * 3. Configure interrupt aggregation
+ * 4. Program UTRL and UTMRL base addres
+ * 5. Configure run-stop-registers
*
* Returns 0 on success, non-zero value on failure
*/
@@ -1017,6 +1095,22 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
goto out;
}
+ /* Enable required interrupts */
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
+
+ /* Configure interrupt aggregation */
+ ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+
+ /* Configure UTRL and UTMRL base address registers */
+ ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
+
/*
* UCRDY, UTMRLDY and UTRLRDY bits must be 1
* DEI, HEI bits must be 0
@@ -1030,17 +1124,11 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
goto out;
}
- /* Enable required interrupts */
- ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
-
- /* Configure interrupt aggregation */
- ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
-
if (hba->ufshcd_state == UFSHCD_STATE_RESET)
scsi_unblock_requests(hba->host);
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
- scsi_scan_host(hba->host);
+
out:
return err;
}
@@ -1109,34 +1197,29 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
}
/**
- * ufshcd_initialize_hba - start the initialization process
+ * ufshcd_link_startup - Initialize unipro link startup
* @hba: per adapter instance
*
- * 1. Enable the controller via ufshcd_hba_enable.
- * 2. Program the Transfer Request List Address with the starting address of
- * UTRDL.
- * 3. Program the Task Management Request List Address with starting address
- * of UTMRDL.
- *
- * Returns 0 on success, non-zero value on failure.
+ * Returns 0 for success, non-zero in case of failure
*/
-static int ufshcd_initialize_hba(struct ufs_hba *hba)
+static int ufshcd_link_startup(struct ufs_hba *hba)
{
- if (ufshcd_hba_enable(hba))
- return -EIO;
+ int ret;
- /* Configure UTRL and UTMRL base address registers */
- ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
- REG_UTP_TRANSFER_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
- REG_UTP_TRANSFER_REQ_LIST_BASE_H);
- ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
- REG_UTP_TASK_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
- REG_UTP_TASK_REQ_LIST_BASE_H);
+ /* enable UIC related interrupts */
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
+
+ ret = ufshcd_dme_link_startup(hba);
+ if (ret)
+ goto out;
- /* Initialize unipro link startup procedure */
- return ufshcd_dme_link_startup(hba);
+ ret = ufshcd_make_hba_operational(hba);
+ if (ret)
+ goto out;
+
+out:
+ dev_err(hba->dev, "link startup failed %d\n", ret);
+ return ret;
}
/**
@@ -1176,12 +1259,19 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
hba->outstanding_reqs = 0;
hba->outstanding_tasks = 0;
- /* start the initialization process */
- if (ufshcd_initialize_hba(hba)) {
+ /* Host controller enable */
+ if (ufshcd_hba_enable(hba)) {
dev_err(hba->dev,
"Reset: Controller initialization failed\n");
return FAILED;
}
+
+ if (ufshcd_link_startup(hba)) {
+ dev_err(hba->dev,
+ "Reset: Link start-up failed\n");
+ return FAILED;
+ }
+
return SUCCESS;
}
@@ -1434,6 +1524,17 @@ 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
+ */
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+{
+ hba->active_uic_cmd->argument2 |=
+ ufshcd_get_uic_cmd_result(hba);
+ complete(&hba->active_uic_cmd->done);
+}
+
+/**
* ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
*/
@@ -1473,28 +1574,6 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
}
/**
- * ufshcd_uic_cc_handler - handle UIC command completion
- * @work: pointer to a work queue structure
- *
- * Returns 0 on success, non-zero value on failure
- */
-static void ufshcd_uic_cc_handler (struct work_struct *work)
-{
- struct ufs_hba *hba;
-
- hba = container_of(work, struct ufs_hba, uic_workq);
-
- if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
- !(ufshcd_get_uic_cmd_result(hba))) {
-
- if (ufshcd_make_hba_operational(hba))
- dev_err(hba->dev,
- "cc: hba not operational state\n");
- return;
- }
-}
-
-/**
* ufshcd_fatal_err_handler - handle fatal errors
* @hba: per adapter instance
*/
@@ -1555,7 +1634,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
ufshcd_err_handler(hba);
if (intr_status & UIC_COMMAND_COMPL)
- schedule_work(&hba->uic_workq);
+ ufshcd_uic_cmd_compl(hba);
if (intr_status & UTP_TASK_REQ_COMPL)
ufshcd_tmc_handler(hba);
@@ -1778,6 +1857,21 @@ out:
return err;
}
+/**
+ * ufshcd_async_scan - asynchronous execution for link startup
+ * @data: data pointer to pass to this function
+ * @cookie: cookie data
+ */
+static void ufshcd_async_scan(void *data, async_cookie_t cookie)
+{
+ struct ufs_hba *hba = (struct ufs_hba *)data;
+ int ret;
+
+ ret = ufshcd_link_startup(hba);
+ if (!ret)
+ scsi_scan_host(hba->host);
+}
+
static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
@@ -1939,12 +2033,14 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
/* Initialize work queues */
- INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
/* Initialize mutex for query requests */
mutex_init(&hba->query.lock_ufs_query);
+ /* Initialize UIC command mutex */
+ mutex_init(&hba->uic_cmd_mutex);
+
/* IRQ registration */
err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
@@ -1965,14 +2061,17 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
goto out_free_irq;
}
- /* Initialization routine */
- err = ufshcd_initialize_hba(hba);
+ /* Host controller enable */
+ err = ufshcd_hba_enable(hba);
if (err) {
- dev_err(hba->dev, "Initialization failed\n");
+ dev_err(hba->dev, "Host controller enable failed\n");
goto out_remove_scsi_host;
}
+
*hba_handle = hba;
+ async_schedule(ufshcd_async_scan, hba);
+
return 0;
out_remove_scsi_host:
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d98e046..974bd07 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -51,6 +51,7 @@
#include <linux/bitops.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -76,6 +77,7 @@
* @argument3: UIC command argument 3
* @cmd_active: Indicate if UIC command is outstanding
* @result: UIC command result
+ * @done: UIC command completion
*/
struct uic_command {
u32 command;
@@ -84,6 +86,7 @@ struct uic_command {
u32 argument3;
int cmd_active;
int result;
+ struct completion done;
};
/**
@@ -150,11 +153,11 @@ struct ufs_query {
* @ufs_version: UFS Version to which controller complies
* @irq: Irq number of the controller
* @active_uic_cmd: handle of active UIC command
+ * @uic_cmd_mutex: mutex for uic command
* @ufshcd_tm_wait_queue: wait queue for task management
* @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
* @intr_mask: Interrupt Mask Bits
- * @uic_workq: Work queue for UIC completion handling
* @feh_workq: Work queue for fatal controller error handling
* @errors: HBA errors
* @query: query request information
@@ -186,7 +189,9 @@ struct ufs_hba {
u32 ufs_version;
unsigned int irq;
- struct uic_command active_uic_cmd;
+ struct uic_command *active_uic_cmd;
+ struct mutex uic_cmd_mutex;
+
wait_queue_head_t ufshcd_tm_wait_queue;
unsigned long tm_condition;
@@ -194,7 +199,6 @@ struct ufs_hba {
u32 intr_mask;
/* Work Queues */
- struct work_struct uic_workq;
struct work_struct feh_workq;
/* HBA Errors */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v3 5/6] scsi: ufs: add dme configuration primitives
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (4 preceding siblings ...)
2013-05-06 5:37 ` [PATCH v3 4/6] scsi: ufs: rework link start-up process Seungwon Jeon
@ 2013-05-06 5:37 ` 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
` (7 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 5:37 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Implements to support Get and Set operation of the DME.
And along with these operations, IDs of Attribute are added.
It is used to configure the behavior of the UNIPRO.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
drivers/scsi/ufs/ufshcd.c | 84 +++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd.h | 30 ++++++++++
drivers/scsi/ufs/ufshci.h | 4 ++
drivers/scsi/ufs/unipro.h | 130 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 248 insertions(+), 0 deletions(-)
create mode 100644 drivers/scsi/ufs/unipro.h
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 118f104..aa06210 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -191,6 +191,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
}
/**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
* ufshcd_free_hba_memory - Free allocated memory for LRB, request
* and task lists
* @hba: Pointer to adapter instance
@@ -1070,6 +1082,76 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
}
/**
+ * ufshcd_dme_xxx_set - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val, u8 peer)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-set",
+ "dme-peer-set"
+ };
+ const char *set = action[!!peer];
+ int ret;
+
+ uic_cmd.command = peer ?
+ UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+ uic_cmd.argument1 = attr_sel;
+ uic_cmd.argument2 = UIC_ARG_ATTR_SET(attr_set);
+ uic_cmd.argument3 = mib_val;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+
+ dev_dbg(hba->dev, "%s: error code %d\n", set, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_set);
+
+/**
+ * ufshcd_dme_xxx_get - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
+ u32 *mib_val, u8 peer)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-get",
+ "dme-peer-get"
+ };
+ const char *get = action[!!peer];
+ int ret;
+
+ uic_cmd.command = peer ?
+ UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+ uic_cmd.argument1 = attr_sel;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+
+ if (mib_val)
+ *mib_val = uic_cmd.argument3;
+
+ dev_dbg(hba->dev, "%s: error code %d\n", get, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
+
+/**
* ufshcd_make_hba_operational - Make UFS controller operational
* @hba: per adapter instance
*
@@ -1531,6 +1613,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
{
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);
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 974bd07..93965b9 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -217,6 +217,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
+extern int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
+ u32 *mib_val, u8 peer);
+
/**
* ufshcd_hba_stop - Send controller to reset state
* @hba: per adapter instance
@@ -226,4 +231,29 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
}
+/* UIC command interfaces for DME primitives */
+static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val)
+{
+ return ufshcd_dme_xxx_set(hba, attr_sel, attr_set, mib_val, 0);
+}
+
+static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val)
+{
+ return ufshcd_dme_xxx_set(hba, attr_sel, attr_set, mib_val, 1);
+}
+
+static inline int ufshcd_dme_get(struct ufs_hba *hba,
+ u32 attr_sel, u32 *mib_val)
+{
+ return ufshcd_dme_xxx_get(hba, attr_sel, mib_val, 0);
+}
+
+static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
+ u32 attr_sel, u32 *mib_val)
+{
+ return ufshcd_dme_xxx_get(hba, attr_sel, mib_val, 1);
+}
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f1e1b74..c7d6a1b 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -191,6 +191,10 @@ enum {
#define CONFIG_RESULT_CODE_MASK 0xFF
#define GENERIC_ERROR_CODE_MASK 0xFF
+#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
+ ((sel) & 0xFFFF))
+#define UIC_ARG_ATTR_SET(type) (((type) & 0xFF) << 16)
+
/* UIC Commands */
enum {
UIC_CMD_DME_GET = 0x01,
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
new file mode 100644
index 0000000..3a710eb
--- /dev/null
+++ b/drivers/scsi/ufs/unipro.h
@@ -0,0 +1,130 @@
+/*
+ * drivers/scsi/ufs/unipro.h
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UNIPRO_H_
+#define _UNIPRO_H_
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES 0x1560
+#define PA_ACTIVERXDATALANES 0x1580
+#define PA_TXTRAILINGCLOCKS 0x1564
+#define PA_PHY_TYPE 0x1500
+#define PA_AVAILTXDATALANES 0x1520
+#define PA_AVAILRXDATALANES 0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
+#define PA_TXPWRSTATUS 0x1567
+#define PA_RXPWRSTATUS 0x1582
+#define PA_TXFORCECLOCK 0x1562
+#define PA_TXPWRMODE 0x1563
+#define PA_LEGACYDPHYESCDL 0x1570
+#define PA_MAXTXSPEEDFAST 0x1521
+#define PA_MAXTXSPEEDSLOW 0x1522
+#define PA_MAXRXSPEEDFAST 0x1541
+#define PA_MAXRXSPEEDSLOW 0x1542
+#define PA_TXLINKSTARTUPHS 0x1544
+#define PA_TXSPEEDFAST 0x1565
+#define PA_TXSPEEDSLOW 0x1566
+#define PA_REMOTEVERINFO 0x15A0
+#define PA_TXGEAR 0x1568
+#define PA_TXTERMINATION 0x1569
+#define PA_HSSERIES 0x156A
+#define PA_PWRMODE 0x1571
+#define PA_RXGEAR 0x1583
+#define PA_RXTERMINATION 0x1584
+#define PA_MAXRXPWMGEAR 0x1586
+#define PA_MAXRXHSGEAR 0x1587
+#define PA_RXHSUNTERMCAP 0x15A5
+#define PA_RXLSTERMCAP 0x15A6
+#define PA_PACPREQTIMEOUT 0x1590
+#define PA_PACPREQEOBTIMEOUT 0x1591
+#define PA_HIBERN8TIME 0x15A7
+#define PA_LOCALVERINFO 0x15A9
+#define PA_TACTIVATE 0x15A8
+#define PA_PACPFRAMECOUNT 0x15C0
+#define PA_PACPERRORCOUNT 0x15C1
+#define PA_PHYTESTCONTROL 0x15C2
+#define PA_PWRMODEUSERDATA0 0x15B0
+#define PA_PWRMODEUSERDATA1 0x15B1
+#define PA_PWRMODEUSERDATA2 0x15B2
+#define PA_PWRMODEUSERDATA3 0x15B3
+#define PA_PWRMODEUSERDATA4 0x15B4
+#define PA_PWRMODEUSERDATA5 0x15B5
+#define PA_PWRMODEUSERDATA6 0x15B6
+#define PA_PWRMODEUSERDATA7 0x15B7
+#define PA_PWRMODEUSERDATA8 0x15B8
+#define PA_PWRMODEUSERDATA9 0x15B9
+#define PA_PWRMODEUSERDATA10 0x15BA
+#define PA_PWRMODEUSERDATA11 0x15BB
+#define PA_CONNECTEDTXDATALANES 0x1561
+#define PA_CONNECTEDRXDATALANES 0x1581
+#define PA_LOGICALLANEMAP 0x15A1
+#define PA_SLEEPNOCONFIGTIME 0x15A2
+#define PA_STALLNOCONFIGTIME 0x15A3
+#define PA_SAVECONFIGTIME 0x15A4
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD 0x2040
+#define DL_FC0PROTTIMEOUTVAL 0x2041
+#define DL_TC0REPLAYTIMEOUTVAL 0x2042
+#define DL_AFC0REQTIMEOUTVAL 0x2043
+#define DL_AFC0CREDITTHRESHOLD 0x2044
+#define DL_TC0OUTACKTHRESHOLD 0x2045
+#define DL_TC1TXFCTHRESHOLD 0x2060
+#define DL_FC1PROTTIMEOUTVAL 0x2061
+#define DL_TC1REPLAYTIMEOUTVAL 0x2062
+#define DL_AFC1REQTIMEOUTVAL 0x2063
+#define DL_AFC1CREDITTHRESHOLD 0x2064
+#define DL_TC1OUTACKTHRESHOLD 0x2065
+#define DL_TXPREEMPTIONCAP 0x2000
+#define DL_TC0TXMAXSDUSIZE 0x2001
+#define DL_TC0RXINITCREDITVAL 0x2002
+#define DL_TC0TXBUFFERSIZE 0x2005
+#define DL_PEERTC0PRESENT 0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
+#define DL_TC1TXMAXSDUSIZE 0x2003
+#define DL_TC1RXINITCREDITVAL 0x2004
+#define DL_TC1TXBUFFERSIZE 0x2006
+#define DL_PEERTC1PRESENT 0x2066
+#define DL_PEERTC1RXINITCREVAL 0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID 0x3000
+#define N_DEVICEID_VALID 0x3001
+#define N_TC0TXMAXSDUSIZE 0x3020
+#define N_TC1TXMAXSDUSIZE 0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS 0x4000
+#define T_NUMTESTFEATURES 0x4001
+#define T_CONNECTIONSTATE 0x4020
+#define T_PEERDEVICEID 0x4021
+#define T_PEERCPORTID 0x4022
+#define T_TRAFFICCLASS 0x4023
+#define T_PROTOCOLID 0x4024
+#define T_CPORTFLAGS 0x4025
+#define T_TXTOKENVALUE 0x4026
+#define T_RXTOKENVALUE 0x4027
+#define T_LOCALBUFFERSPACE 0x4028
+#define T_PEERBUFFERSPACE 0x4029
+#define T_CREDITSTOSEND 0x402A
+#define T_CPORTMODE 0x402B
+#define T_TC0TXMAXSDUSIZE 0x4060
+#define T_TC1TXMAXSDUSIZE 0x4061
+
+#endif /* _UNIPRO_H_ */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v3 6/6] scsi: ufs: add dme control primitives
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (5 preceding siblings ...)
2013-05-06 5:37 ` [PATCH v3 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
@ 2013-05-06 5:39 ` Seungwon Jeon
2013-05-06 19:51 ` Santosh Y
2013-05-08 8:41 ` [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations Seungwon Jeon
` (6 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 5:39 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
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>
---
drivers/scsi/ufs/ufshcd.c | 132 ++++++++++++++++++++++++++++++++++++++++++---
drivers/scsi/ufs/ufshcd.h | 26 +++++++++
drivers/scsi/ufs/ufshci.h | 15 +++++
3 files changed, 165 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index aa06210..3607ffb 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
@@ -1152,6 +1165,103 @@ int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
/**
+ * ufshcd_dme_power_xxx - 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_xxx(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_xxx);
+
+/**
+ * ufshcd_dme_hibern8_xxx - 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_xxx(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:%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_xxx);
+
+/**
+ * ufshcd_dme_endpt_reset - UIC command for DME_ENDPOINTRESET
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_endpt_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, "endpoint reset: error code %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_endpt_reset);
+
+/**
* ufshcd_make_hba_operational - Make UFS controller operational
* @hba: per adapter instance
*
@@ -1608,14 +1718,20 @@ 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)
{
- 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 & UIC_COMMAND_COMPL) {
+ 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);
}
/**
@@ -1717,8 +1833,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 93965b9..84f758e 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_xxx_set(struct ufs_hba *hba, u32 attr_sel,
u8 attr_set, u32 mib_val, u8 peer);
extern int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
u32 *mib_val, u8 peer);
+extern int ufshcd_dme_power_xxx(struct ufs_hba *hba, u8 on);
+extern int ufshcd_dme_hibern8_xxx(struct ufs_hba *hba, u8 enter);
+extern int ufshcd_dme_endpt_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_xxx_get(hba, attr_sel, mib_val, 1);
}
+static inline int ufshcd_dme_power_on(struct ufs_hba *hba)
+{
+ return ufshcd_dme_power_xxx(hba, 1);
+}
+
+static inline int ufshcd_dme_power_off(struct ufs_hba *hba)
+{
+ return ufshcd_dme_power_xxx(hba, 0);
+}
+
+static inline int ufshcd_dme_hibern8_enter(struct ufs_hba *hba)
+{
+ return ufshcd_dme_hibern8_xxx(hba, 1);
+}
+
+static inline int ufshcd_dme_hibern8_exit(struct ufs_hba *hba)
+{
+ return ufshcd_dme_hibern8_xxx(hba, 0);
+}
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index c7d6a1b..d60703f 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
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH v3 4/6] scsi: ufs: rework link start-up process
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
0 siblings, 2 replies; 52+ messages in thread
From: Sujit Reddy Thumma @ 2013-05-06 9:47 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
On 5/6/2013 11:07 AM, Seungwon Jeon wrote:
> Link start-up requires long time with multiphase handshakes
> between UFS host and device. This affects driver's probe time.
> This patch let link start-up run asynchronously. Link start-up
> will be executed at the end of prove separately.
> Along with this change, the following is worked.
>
> Defined completion time of uic command to avoid a permanent wait.
We have seen a kernel crash when the timeout happens in our internal
testing. This is basically because the the UIC_CMD_TIMEOUT of 500msec is
less for our platform. We see UIC_COMMAND_COMPL interrupt after this
timeout and since uic_cmd is freed we see a kernel crash.
[ 6.026094] ufshcd 0000:01:00.0: link startup: error code -110
[ 6.030886] ufshcd 0000:01:00.0: link startup failed -110
...
[ 6.487288] BUG: spinlock bad magic on CPU#0, swapper/0/0
[ 6.491683] Unable to handle kernel paging request at virtual address
6000012b
...
[ 7.625270] [<c07c3718>] (spin_dump+0x4c/0x88) from [<c02ab9d8>]
(do_raw_spin_lock+0x20/0x154)
[ 7.633877] [<c02ab9d8>] (do_raw_spin_lock+0x20/0x154) from
[<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30)
[ 7.643583] [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30) from
[<c00a3c98>] (complete+0x1c/0x58)
[ 7.652525] [<c00a3c98>] (complete+0x1c/0x58) from [<c03d10c4>]
(ufshcd_intr+0x1a8/0x498)
[ 7.660705] [<c03d10c4>] (ufshcd_intr+0x1a8/0x498) from [<c00cff48>]
(handle_irq_event_percpu+0xb0/0x290)
[ 7.670227] [<c00cff48>] (handle_irq_event_percpu+0xb0/0x290) from
[<c00d0164>] (handle_irq_event+0x3c/0x5c)
[ 7.680054] [<c00d0164>] (handle_irq_event+0x3c/0x5c) from
[<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148)
[ 7.689424] [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148) from
[<c00cf7ac>] (generic_handle_irq+0x30/0x44)
[ 7.698977] [<c00cf7ac>] (generic_handle_irq+0x30/0x44) from
[<c000ee40>] (handle_IRQ+0x7c/0xc0)
[ 7.707736] [<c000ee40>] (handle_IRQ+0x7c/0xc0) from [<c0008620>]
(gic_handle_irq+0x94/0x110)
[ 7.716252] [<c0008620>] (gic_handle_irq+0x94/0x110) from
[<c07ccec0>] (__irq_svc+0x40/0x70)
Following would fix this. Please check. Also, we need to increase the
timeout to say 5 secs to avoid such races.
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ecbae40..ae22a8e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -485,6 +485,7 @@ static int
ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
{
int ret;
+ unsigned long flags;
if (wait_for_completion_timeout(&uic_cmd->done,
msecs_to_jiffies(UIC_CMD_TIMEOUT)))
@@ -492,6 +493,10 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct
uic_command *uic_cmd)
else
ret = -ETIMEDOUT;
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->active_uic_cmd = NULL;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
return ret;
}
@@ -1842,7 +1847,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
struct ufshcd_lrb *lrbp)
*/
static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
{
- if (intr_status & UIC_COMMAND_COMPL) {
+ if (hba->active_uic_cmd && (intr_status & UIC_COMMAND_COMPL)) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
> Added mutex to guarantee of uic command at a time.
> Adapted some sequence of controller initialization after link statup
> according to HCI standard.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 287 ++++++++++++++++++++++++++++++---------------
> drivers/scsi/ufs/ufshcd.h | 10 +-
> 2 files changed, 200 insertions(+), 97 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index e04c74e..118f104 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -33,11 +33,15 @@
> * this program.
> */
>
> +#include <linux/async.h>
> +
> #include "ufshcd.h"
>
> #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
> UTP_TASK_REQ_COMPL |\
> UFSHCD_ERROR_MASK)
> +/* UIC command timeout, unit: ms */
> +#define UIC_CMD_TIMEOUT 500
>
> enum {
> UFSHCD_MAX_CHANNEL = 0,
> @@ -401,24 +405,115 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> }
>
> /**
> - * ufshcd_send_uic_command - Send UIC commands to unipro layers
> + * ufshcd_ready_for_uic_cmd - Check if controller is ready
> + * to accept UIC commands
> * @hba: per adapter instance
> - * @uic_command: UIC command
> + * Return true on success, else false
> + */
> +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
> +{
> + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
> + return true;
> + else
> + return false;
> +}
> +
> +/**
> + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> + * @hba: per adapter instance
> + * @uic_cmd: UIC command
> + *
> + * Mutex must be held.
> */
> static inline void
> -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> {
> + hba->active_uic_cmd = uic_cmd;
> +
> /* Write Args */
> - ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> - ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> - ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
> + ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
> + ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
> + ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
>
> /* Write UIC Cmd */
> - ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> + ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
> REG_UIC_COMMAND);
> }
>
> /**
> + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
> + * @hba: per adapter instance
> + * @uic_command: UIC command
> + *
> + * Must be called with mutex held.
> + * Returns 0 only if success.
> + */
> +static int
> +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> +{
> + int ret;
> +
> + if (wait_for_completion_timeout(&uic_cmd->done,
> + msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> + ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
> + else
> + ret = -ETIMEDOUT;
> +
> + return ret;
> +}
> +
> +/**
> + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
> + * @hba: per adapter instance
> + * @uic_cmd: UIC command
> + *
> + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
> + * with mutex held.
> + * Returns 0 only if success.
> + */
> +static int
> +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> +{
> + int ret;
> + unsigned long flags;
> +
> + if (!ufshcd_ready_for_uic_cmd(hba)) {
> + dev_err(hba->dev,
> + "Controller not ready to accept UIC commands\n");
> + return -EIO;
> + }
> +
> + init_completion(&uic_cmd->done);
> +
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + ufshcd_dispatch_uic_cmd(hba, uic_cmd);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
> +
> + return ret;
> +}
> +
> +/**
> + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
> + * @hba: per adapter instance
> + * @uic_cmd: UIC command
> + *
> + * Returns 0 only if success.
> + */
> +static int
> +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> +{
> + int ret;
> +
> + mutex_lock(&hba->uic_cmd_mutex);
> + ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
> + mutex_unlock(&hba->uic_cmd_mutex);
> +
> + return ret;
> +}
> +
> +/**
> * ufshcd_map_sg - Map scatter-gather list to prdt
> * @lrbp - pointer to local reference block
> *
> @@ -962,34 +1057,16 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
> */
> static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> {
> - struct uic_command *uic_cmd;
> - unsigned long flags;
> + struct uic_command uic_cmd = {0};
> + int ret;
>
> - /* check if controller is ready to accept UIC commands */
> - if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> - UIC_COMMAND_READY) == 0x0) {
> - dev_err(hba->dev,
> - "Controller not ready"
> - " to accept UIC commands\n");
> - return -EIO;
> - }
> -
> - spin_lock_irqsave(hba->host->host_lock, flags);
> + uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
>
> - /* form UIC command */
> - uic_cmd = &hba->active_uic_cmd;
> - uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
> - uic_cmd->argument1 = 0;
> - uic_cmd->argument2 = 0;
> - uic_cmd->argument3 = 0;
> -
> - /* enable UIC related interrupts */
> - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
> -
> - /* sending UIC commands to controller */
> - ufshcd_send_uic_command(hba, uic_cmd);
> - spin_unlock_irqrestore(hba->host->host_lock, flags);
> - return 0;
> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> + if (ret)
> + dev_err(hba->dev,
> + "link startup: error code %d\n", ret);
> + return ret;
> }
>
> /**
> @@ -998,9 +1075,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> *
> * To bring UFS host controller to operational state,
> * 1. Check if device is present
> - * 2. Configure run-stop-registers
> - * 3. Enable required interrupts
> - * 4. Configure interrupt aggregation
> + * 2. Enable required interrupts
> + * 3. Configure interrupt aggregation
> + * 4. Program UTRL and UTMRL base addres
> + * 5. Configure run-stop-registers
> *
> * Returns 0 on success, non-zero value on failure
> */
> @@ -1017,6 +1095,22 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> goto out;
> }
>
> + /* Enable required interrupts */
> + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
> +
> + /* Configure interrupt aggregation */
> + ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> +
> + /* Configure UTRL and UTMRL base address registers */
> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_H);
> +
> /*
> * UCRDY, UTMRLDY and UTRLRDY bits must be 1
> * DEI, HEI bits must be 0
> @@ -1030,17 +1124,11 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> goto out;
> }
>
> - /* Enable required interrupts */
> - ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
> -
> - /* Configure interrupt aggregation */
> - ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> -
> if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> scsi_unblock_requests(hba->host);
>
> hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
> - scsi_scan_host(hba->host);
> +
> out:
> return err;
> }
> @@ -1109,34 +1197,29 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
> }
>
> /**
> - * ufshcd_initialize_hba - start the initialization process
> + * ufshcd_link_startup - Initialize unipro link startup
> * @hba: per adapter instance
> *
> - * 1. Enable the controller via ufshcd_hba_enable.
> - * 2. Program the Transfer Request List Address with the starting address of
> - * UTRDL.
> - * 3. Program the Task Management Request List Address with starting address
> - * of UTMRDL.
> - *
> - * Returns 0 on success, non-zero value on failure.
> + * Returns 0 for success, non-zero in case of failure
> */
> -static int ufshcd_initialize_hba(struct ufs_hba *hba)
> +static int ufshcd_link_startup(struct ufs_hba *hba)
> {
> - if (ufshcd_hba_enable(hba))
> - return -EIO;
> + int ret;
>
> - /* Configure UTRL and UTMRL base address registers */
> - ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> - REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> - ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> - REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> - ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> - REG_UTP_TASK_REQ_LIST_BASE_L);
> - ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> - REG_UTP_TASK_REQ_LIST_BASE_H);
> + /* enable UIC related interrupts */
> + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
> +
> + ret = ufshcd_dme_link_startup(hba);
> + if (ret)
> + goto out;
>
> - /* Initialize unipro link startup procedure */
> - return ufshcd_dme_link_startup(hba);
> + ret = ufshcd_make_hba_operational(hba);
> + if (ret)
> + goto out;
> +
> +out:
> + dev_err(hba->dev, "link startup failed %d\n", ret);
> + return ret;
> }
>
> /**
> @@ -1176,12 +1259,19 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
> hba->outstanding_reqs = 0;
> hba->outstanding_tasks = 0;
>
> - /* start the initialization process */
> - if (ufshcd_initialize_hba(hba)) {
> + /* Host controller enable */
> + if (ufshcd_hba_enable(hba)) {
> dev_err(hba->dev,
> "Reset: Controller initialization failed\n");
> return FAILED;
> }
> +
> + if (ufshcd_link_startup(hba)) {
> + dev_err(hba->dev,
> + "Reset: Link start-up failed\n");
> + return FAILED;
> + }
> +
> return SUCCESS;
> }
>
> @@ -1434,6 +1524,17 @@ 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
> + */
> +static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
> +{
> + hba->active_uic_cmd->argument2 |=
> + ufshcd_get_uic_cmd_result(hba);
> + complete(&hba->active_uic_cmd->done);
> +}
> +
> +/**
> * ufshcd_transfer_req_compl - handle SCSI and query command completion
> * @hba: per adapter instance
> */
> @@ -1473,28 +1574,6 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
> }
>
> /**
> - * ufshcd_uic_cc_handler - handle UIC command completion
> - * @work: pointer to a work queue structure
> - *
> - * Returns 0 on success, non-zero value on failure
> - */
> -static void ufshcd_uic_cc_handler (struct work_struct *work)
> -{
> - struct ufs_hba *hba;
> -
> - hba = container_of(work, struct ufs_hba, uic_workq);
> -
> - if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
> - !(ufshcd_get_uic_cmd_result(hba))) {
> -
> - if (ufshcd_make_hba_operational(hba))
> - dev_err(hba->dev,
> - "cc: hba not operational state\n");
> - return;
> - }
> -}
> -
> -/**
> * ufshcd_fatal_err_handler - handle fatal errors
> * @hba: per adapter instance
> */
> @@ -1555,7 +1634,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
> ufshcd_err_handler(hba);
>
> if (intr_status & UIC_COMMAND_COMPL)
> - schedule_work(&hba->uic_workq);
> + ufshcd_uic_cmd_compl(hba);
>
> if (intr_status & UTP_TASK_REQ_COMPL)
> ufshcd_tmc_handler(hba);
> @@ -1778,6 +1857,21 @@ out:
> return err;
> }
>
> +/**
> + * ufshcd_async_scan - asynchronous execution for link startup
> + * @data: data pointer to pass to this function
> + * @cookie: cookie data
> + */
> +static void ufshcd_async_scan(void *data, async_cookie_t cookie)
> +{
> + struct ufs_hba *hba = (struct ufs_hba *)data;
> + int ret;
> +
> + ret = ufshcd_link_startup(hba);
> + if (!ret)
> + scsi_scan_host(hba->host);
> +}
> +
> static struct scsi_host_template ufshcd_driver_template = {
> .module = THIS_MODULE,
> .name = UFSHCD,
> @@ -1939,12 +2033,14 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
>
> /* Initialize work queues */
> - INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
> INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
>
> /* Initialize mutex for query requests */
> mutex_init(&hba->query.lock_ufs_query);
>
> + /* Initialize UIC command mutex */
> + mutex_init(&hba->uic_cmd_mutex);
> +
> /* IRQ registration */
> err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
> if (err) {
> @@ -1965,14 +2061,17 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> goto out_free_irq;
> }
>
> - /* Initialization routine */
> - err = ufshcd_initialize_hba(hba);
> + /* Host controller enable */
> + err = ufshcd_hba_enable(hba);
> if (err) {
> - dev_err(hba->dev, "Initialization failed\n");
> + dev_err(hba->dev, "Host controller enable failed\n");
> goto out_remove_scsi_host;
> }
> +
> *hba_handle = hba;
>
> + async_schedule(ufshcd_async_scan, hba);
> +
> return 0;
>
> out_remove_scsi_host:
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index d98e046..974bd07 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -51,6 +51,7 @@
> #include <linux/bitops.h>
> #include <linux/pm_runtime.h>
> #include <linux/clk.h>
> +#include <linux/completion.h>
>
> #include <asm/irq.h>
> #include <asm/byteorder.h>
> @@ -76,6 +77,7 @@
> * @argument3: UIC command argument 3
> * @cmd_active: Indicate if UIC command is outstanding
> * @result: UIC command result
> + * @done: UIC command completion
> */
> struct uic_command {
> u32 command;
> @@ -84,6 +86,7 @@ struct uic_command {
> u32 argument3;
> int cmd_active;
> int result;
> + struct completion done;
> };
>
> /**
> @@ -150,11 +153,11 @@ struct ufs_query {
> * @ufs_version: UFS Version to which controller complies
> * @irq: Irq number of the controller
> * @active_uic_cmd: handle of active UIC command
> + * @uic_cmd_mutex: mutex for uic command
> * @ufshcd_tm_wait_queue: wait queue for task management
> * @tm_condition: condition variable for task management
> * @ufshcd_state: UFSHCD states
> * @intr_mask: Interrupt Mask Bits
> - * @uic_workq: Work queue for UIC completion handling
> * @feh_workq: Work queue for fatal controller error handling
> * @errors: HBA errors
> * @query: query request information
> @@ -186,7 +189,9 @@ struct ufs_hba {
> u32 ufs_version;
> unsigned int irq;
>
> - struct uic_command active_uic_cmd;
> + struct uic_command *active_uic_cmd;
> + struct mutex uic_cmd_mutex;
> +
> wait_queue_head_t ufshcd_tm_wait_queue;
> unsigned long tm_condition;
>
> @@ -194,7 +199,6 @@ struct ufs_hba {
> u32 intr_mask;
>
> /* Work Queues */
> - struct work_struct uic_workq;
> struct work_struct feh_workq;
>
> /* HBA Errors */
>
--
Regards,
Sujit
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH v3 4/6] scsi: ufs: rework link start-up process
2013-05-06 9:47 ` Sujit Reddy Thumma
@ 2013-05-06 10:36 ` merez
2013-05-06 11:21 ` Seungwon Jeon
1 sibling, 0 replies; 52+ messages in thread
From: merez @ 2013-05-06 10:36 UTC (permalink / raw)
To: Sujit Reddy Thumma
Cc: Seungwon Jeon, linux-scsi, 'Vinayak Holikatti',
'Santosh Y', 'James E.J. Bottomley'
Hi,
The proposed fix fixes the timeout crash.
In normal operation the patch works, so after applying the fix you can add
my Tested-By.
One additional minor fix that is required:
In ufshcd_link_startup the following print-out is printed in success as well:
dev_err(hba->dev, "link startup failed %d\n", ret);
Please move it to the error cases only.
Thanks,
Maya
> On 5/6/2013 11:07 AM, Seungwon Jeon wrote:
>> Link start-up requires long time with multiphase handshakes
>> between UFS host and device. This affects driver's probe time.
>> This patch let link start-up run asynchronously. Link start-up
>> will be executed at the end of prove separately.
>> Along with this change, the following is worked.
>>
>> Defined completion time of uic command to avoid a permanent wait.
> We have seen a kernel crash when the timeout happens in our internal
> testing. This is basically because the the UIC_CMD_TIMEOUT of 500msec is
> less for our platform. We see UIC_COMMAND_COMPL interrupt after this
> timeout and since uic_cmd is freed we see a kernel crash.
>
> [ 6.026094] ufshcd 0000:01:00.0: link startup: error code -110
> [ 6.030886] ufshcd 0000:01:00.0: link startup failed -110
> ...
>
> [ 6.487288] BUG: spinlock bad magic on CPU#0, swapper/0/0
> [ 6.491683] Unable to handle kernel paging request at virtual address
> 6000012b
> ...
> [ 7.625270] [<c07c3718>] (spin_dump+0x4c/0x88) from [<c02ab9d8>]
> (do_raw_spin_lock+0x20/0x154)
> [ 7.633877] [<c02ab9d8>] (do_raw_spin_lock+0x20/0x154) from
> [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30)
> [ 7.643583] [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30) from
> [<c00a3c98>] (complete+0x1c/0x58)
> [ 7.652525] [<c00a3c98>] (complete+0x1c/0x58) from [<c03d10c4>]
> (ufshcd_intr+0x1a8/0x498)
> [ 7.660705] [<c03d10c4>] (ufshcd_intr+0x1a8/0x498) from [<c00cff48>]
> (handle_irq_event_percpu+0xb0/0x290)
> [ 7.670227] [<c00cff48>] (handle_irq_event_percpu+0xb0/0x290) from
> [<c00d0164>] (handle_irq_event+0x3c/0x5c)
> [ 7.680054] [<c00d0164>] (handle_irq_event+0x3c/0x5c) from
> [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148)
> [ 7.689424] [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148) from
> [<c00cf7ac>] (generic_handle_irq+0x30/0x44)
> [ 7.698977] [<c00cf7ac>] (generic_handle_irq+0x30/0x44) from
> [<c000ee40>] (handle_IRQ+0x7c/0xc0)
> [ 7.707736] [<c000ee40>] (handle_IRQ+0x7c/0xc0) from [<c0008620>]
> (gic_handle_irq+0x94/0x110)
> [ 7.716252] [<c0008620>] (gic_handle_irq+0x94/0x110) from
> [<c07ccec0>] (__irq_svc+0x40/0x70)
>
>
> Following would fix this. Please check. Also, we need to increase the
> timeout to say 5 secs to avoid such races.
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index ecbae40..ae22a8e 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -485,6 +485,7 @@ static int
> ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> {
> int ret;
> + unsigned long flags;
>
> if (wait_for_completion_timeout(&uic_cmd->done,
> msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> @@ -492,6 +493,10 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct
> uic_command *uic_cmd)
> else
> ret = -ETIMEDOUT;
>
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + hba->active_uic_cmd = NULL;
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> return ret;
> }
>
> @@ -1842,7 +1847,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
> */
> static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
> {
> - if (intr_status & UIC_COMMAND_COMPL) {
> + if (hba->active_uic_cmd && (intr_status & UIC_COMMAND_COMPL)) {
> hba->active_uic_cmd->argument2 |=
> ufshcd_get_uic_cmd_result(hba);
> hba->active_uic_cmd->argument3 =
>
>
>> Added mutex to guarantee of uic command at a time.
>> Adapted some sequence of controller initialization after link statup
>> according to HCI standard.
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
>> ---
>> drivers/scsi/ufs/ufshcd.c | 287
>> ++++++++++++++++++++++++++++++---------------
>> drivers/scsi/ufs/ufshcd.h | 10 +-
>> 2 files changed, 200 insertions(+), 97 deletions(-)
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> index e04c74e..118f104 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -33,11 +33,15 @@
>> * this program.
>> */
>>
>> +#include <linux/async.h>
>> +
>> #include "ufshcd.h"
>>
>> #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
>> UTP_TASK_REQ_COMPL |\
>> UFSHCD_ERROR_MASK)
>> +/* UIC command timeout, unit: ms */
>> +#define UIC_CMD_TIMEOUT 500
>>
>> enum {
>> UFSHCD_MAX_CHANNEL = 0,
>> @@ -401,24 +405,115 @@ static inline void ufshcd_hba_capabilities(struct
>> ufs_hba *hba)
>> }
>>
>> /**
>> - * ufshcd_send_uic_command - Send UIC commands to unipro layers
>> + * ufshcd_ready_for_uic_cmd - Check if controller is ready
>> + * to accept UIC commands
>> * @hba: per adapter instance
>> - * @uic_command: UIC command
>> + * Return true on success, else false
>> + */
>> +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
>> +{
>> + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
>> + return true;
>> + else
>> + return false;
>> +}
>> +
>> +/**
>> + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
>> + * @hba: per adapter instance
>> + * @uic_cmd: UIC command
>> + *
>> + * Mutex must be held.
>> */
>> static inline void
>> -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command
>> *uic_cmnd)
>> +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command
>> *uic_cmd)
>> {
>> + hba->active_uic_cmd = uic_cmd;
>> +
>> /* Write Args */
>> - ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
>> - ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
>> - ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
>> + ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
>> + ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
>> + ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
>>
>> /* Write UIC Cmd */
>> - ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
>> + ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
>> REG_UIC_COMMAND);
>> }
>>
>> /**
>> + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
>> + * @hba: per adapter instance
>> + * @uic_command: UIC command
>> + *
>> + * Must be called with mutex held.
>> + * Returns 0 only if success.
>> + */
>> +static int
>> +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command
>> *uic_cmd)
>> +{
>> + int ret;
>> +
>> + if (wait_for_completion_timeout(&uic_cmd->done,
>> + msecs_to_jiffies(UIC_CMD_TIMEOUT)))
>> + ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
>> + else
>> + ret = -ETIMEDOUT;
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
>> + * @hba: per adapter instance
>> + * @uic_cmd: UIC command
>> + *
>> + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
>> + * with mutex held.
>> + * Returns 0 only if success.
>> + */
>> +static int
>> +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
>> +{
>> + int ret;
>> + unsigned long flags;
>> +
>> + if (!ufshcd_ready_for_uic_cmd(hba)) {
>> + dev_err(hba->dev,
>> + "Controller not ready to accept UIC commands\n");
>> + return -EIO;
>> + }
>> +
>> + init_completion(&uic_cmd->done);
>> +
>> + spin_lock_irqsave(hba->host->host_lock, flags);
>> + ufshcd_dispatch_uic_cmd(hba, uic_cmd);
>> + spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
>> + * @hba: per adapter instance
>> + * @uic_cmd: UIC command
>> + *
>> + * Returns 0 only if success.
>> + */
>> +static int
>> +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&hba->uic_cmd_mutex);
>> + ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
>> + mutex_unlock(&hba->uic_cmd_mutex);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> * ufshcd_map_sg - Map scatter-gather list to prdt
>> * @lrbp - pointer to local reference block
>> *
>> @@ -962,34 +1057,16 @@ static void ufshcd_host_memory_configure(struct
>> ufs_hba *hba)
>> */
>> static int ufshcd_dme_link_startup(struct ufs_hba *hba)
>> {
>> - struct uic_command *uic_cmd;
>> - unsigned long flags;
>> + struct uic_command uic_cmd = {0};
>> + int ret;
>>
>> - /* check if controller is ready to accept UIC commands */
>> - if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
>> - UIC_COMMAND_READY) == 0x0) {
>> - dev_err(hba->dev,
>> - "Controller not ready"
>> - " to accept UIC commands\n");
>> - return -EIO;
>> - }
>> -
>> - spin_lock_irqsave(hba->host->host_lock, flags);
>> + uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
>>
>> - /* form UIC command */
>> - uic_cmd = &hba->active_uic_cmd;
>> - uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
>> - uic_cmd->argument1 = 0;
>> - uic_cmd->argument2 = 0;
>> - uic_cmd->argument3 = 0;
>> -
>> - /* enable UIC related interrupts */
>> - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>> -
>> - /* sending UIC commands to controller */
>> - ufshcd_send_uic_command(hba, uic_cmd);
>> - spin_unlock_irqrestore(hba->host->host_lock, flags);
>> - return 0;
>> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
>> + if (ret)
>> + dev_err(hba->dev,
>> + "link startup: error code %d\n", ret);
>> + return ret;
>> }
>>
>> /**
>> @@ -998,9 +1075,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba
>> *hba)
>> *
>> * To bring UFS host controller to operational state,
>> * 1. Check if device is present
>> - * 2. Configure run-stop-registers
>> - * 3. Enable required interrupts
>> - * 4. Configure interrupt aggregation
>> + * 2. Enable required interrupts
>> + * 3. Configure interrupt aggregation
>> + * 4. Program UTRL and UTMRL base addres
>> + * 5. Configure run-stop-registers
>> *
>> * Returns 0 on success, non-zero value on failure
>> */
>> @@ -1017,6 +1095,22 @@ static int ufshcd_make_hba_operational(struct
>> ufs_hba *hba)
>> goto out;
>> }
>>
>> + /* Enable required interrupts */
>> + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
>> +
>> + /* Configure interrupt aggregation */
>> + ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
>> +
>> + /* Configure UTRL and UTMRL base address registers */
>> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
>> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
>> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
>> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
>> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
>> + REG_UTP_TASK_REQ_LIST_BASE_L);
>> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
>> + REG_UTP_TASK_REQ_LIST_BASE_H);
>> +
>> /*
>> * UCRDY, UTMRLDY and UTRLRDY bits must be 1
>> * DEI, HEI bits must be 0
>> @@ -1030,17 +1124,11 @@ static int ufshcd_make_hba_operational(struct
>> ufs_hba *hba)
>> goto out;
>> }
>>
>> - /* Enable required interrupts */
>> - ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
>> -
>> - /* Configure interrupt aggregation */
>> - ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
>> -
>> if (hba->ufshcd_state == UFSHCD_STATE_RESET)
>> scsi_unblock_requests(hba->host);
>>
>> hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
>> - scsi_scan_host(hba->host);
>> +
>> out:
>> return err;
>> }
>> @@ -1109,34 +1197,29 @@ static int ufshcd_hba_enable(struct ufs_hba
>> *hba)
>> }
>>
>> /**
>> - * ufshcd_initialize_hba - start the initialization process
>> + * ufshcd_link_startup - Initialize unipro link startup
>> * @hba: per adapter instance
>> *
>> - * 1. Enable the controller via ufshcd_hba_enable.
>> - * 2. Program the Transfer Request List Address with the starting
>> address of
>> - * UTRDL.
>> - * 3. Program the Task Management Request List Address with starting
>> address
>> - * of UTMRDL.
>> - *
>> - * Returns 0 on success, non-zero value on failure.
>> + * Returns 0 for success, non-zero in case of failure
>> */
>> -static int ufshcd_initialize_hba(struct ufs_hba *hba)
>> +static int ufshcd_link_startup(struct ufs_hba *hba)
>> {
>> - if (ufshcd_hba_enable(hba))
>> - return -EIO;
>> + int ret;
>>
>> - /* Configure UTRL and UTMRL base address registers */
>> - ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
>> - REG_UTP_TRANSFER_REQ_LIST_BASE_L);
>> - ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
>> - REG_UTP_TRANSFER_REQ_LIST_BASE_H);
>> - ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
>> - REG_UTP_TASK_REQ_LIST_BASE_L);
>> - ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
>> - REG_UTP_TASK_REQ_LIST_BASE_H);
>> + /* enable UIC related interrupts */
>> + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>> +
>> + ret = ufshcd_dme_link_startup(hba);
>> + if (ret)
>> + goto out;
>>
>> - /* Initialize unipro link startup procedure */
>> - return ufshcd_dme_link_startup(hba);
>> + ret = ufshcd_make_hba_operational(hba);
>> + if (ret)
>> + goto out;
>> +
>> +out:
>> + dev_err(hba->dev, "link startup failed %d\n", ret);
>> + return ret;
>> }
>>
>> /**
>> @@ -1176,12 +1259,19 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
>> hba->outstanding_reqs = 0;
>> hba->outstanding_tasks = 0;
>>
>> - /* start the initialization process */
>> - if (ufshcd_initialize_hba(hba)) {
>> + /* Host controller enable */
>> + if (ufshcd_hba_enable(hba)) {
>> dev_err(hba->dev,
>> "Reset: Controller initialization failed\n");
>> return FAILED;
>> }
>> +
>> + if (ufshcd_link_startup(hba)) {
>> + dev_err(hba->dev,
>> + "Reset: Link start-up failed\n");
>> + return FAILED;
>> + }
>> +
>> return SUCCESS;
>> }
>>
>> @@ -1434,6 +1524,17 @@ 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
>> + */
>> +static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
>> +{
>> + hba->active_uic_cmd->argument2 |=
>> + ufshcd_get_uic_cmd_result(hba);
>> + complete(&hba->active_uic_cmd->done);
>> +}
>> +
>> +/**
>> * ufshcd_transfer_req_compl - handle SCSI and query command
>> completion
>> * @hba: per adapter instance
>> */
>> @@ -1473,28 +1574,6 @@ static void ufshcd_transfer_req_compl(struct
>> ufs_hba *hba)
>> }
>>
>> /**
>> - * ufshcd_uic_cc_handler - handle UIC command completion
>> - * @work: pointer to a work queue structure
>> - *
>> - * Returns 0 on success, non-zero value on failure
>> - */
>> -static void ufshcd_uic_cc_handler (struct work_struct *work)
>> -{
>> - struct ufs_hba *hba;
>> -
>> - hba = container_of(work, struct ufs_hba, uic_workq);
>> -
>> - if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
>> - !(ufshcd_get_uic_cmd_result(hba))) {
>> -
>> - if (ufshcd_make_hba_operational(hba))
>> - dev_err(hba->dev,
>> - "cc: hba not operational state\n");
>> - return;
>> - }
>> -}
>> -
>> -/**
>> * ufshcd_fatal_err_handler - handle fatal errors
>> * @hba: per adapter instance
>> */
>> @@ -1555,7 +1634,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba,
>> u32 intr_status)
>> ufshcd_err_handler(hba);
>>
>> if (intr_status & UIC_COMMAND_COMPL)
>> - schedule_work(&hba->uic_workq);
>> + ufshcd_uic_cmd_compl(hba);
>>
>> if (intr_status & UTP_TASK_REQ_COMPL)
>> ufshcd_tmc_handler(hba);
>> @@ -1778,6 +1857,21 @@ out:
>> return err;
>> }
>>
>> +/**
>> + * ufshcd_async_scan - asynchronous execution for link startup
>> + * @data: data pointer to pass to this function
>> + * @cookie: cookie data
>> + */
>> +static void ufshcd_async_scan(void *data, async_cookie_t cookie)
>> +{
>> + struct ufs_hba *hba = (struct ufs_hba *)data;
>> + int ret;
>> +
>> + ret = ufshcd_link_startup(hba);
>> + if (!ret)
>> + scsi_scan_host(hba->host);
>> +}
>> +
>> static struct scsi_host_template ufshcd_driver_template = {
>> .module = THIS_MODULE,
>> .name = UFSHCD,
>> @@ -1939,12 +2033,14 @@ int ufshcd_init(struct device *dev, struct
>> ufs_hba **hba_handle,
>> init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
>>
>> /* Initialize work queues */
>> - INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
>> INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
>>
>> /* Initialize mutex for query requests */
>> mutex_init(&hba->query.lock_ufs_query);
>>
>> + /* Initialize UIC command mutex */
>> + mutex_init(&hba->uic_cmd_mutex);
>> +
>> /* IRQ registration */
>> err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
>> if (err) {
>> @@ -1965,14 +2061,17 @@ int ufshcd_init(struct device *dev, struct
>> ufs_hba **hba_handle,
>> goto out_free_irq;
>> }
>>
>> - /* Initialization routine */
>> - err = ufshcd_initialize_hba(hba);
>> + /* Host controller enable */
>> + err = ufshcd_hba_enable(hba);
>> if (err) {
>> - dev_err(hba->dev, "Initialization failed\n");
>> + dev_err(hba->dev, "Host controller enable failed\n");
>> goto out_remove_scsi_host;
>> }
>> +
>> *hba_handle = hba;
>>
>> + async_schedule(ufshcd_async_scan, hba);
>> +
>> return 0;
>>
>> out_remove_scsi_host:
>> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
>> index d98e046..974bd07 100644
>> --- a/drivers/scsi/ufs/ufshcd.h
>> +++ b/drivers/scsi/ufs/ufshcd.h
>> @@ -51,6 +51,7 @@
>> #include <linux/bitops.h>
>> #include <linux/pm_runtime.h>
>> #include <linux/clk.h>
>> +#include <linux/completion.h>
>>
>> #include <asm/irq.h>
>> #include <asm/byteorder.h>
>> @@ -76,6 +77,7 @@
>> * @argument3: UIC command argument 3
>> * @cmd_active: Indicate if UIC command is outstanding
>> * @result: UIC command result
>> + * @done: UIC command completion
>> */
>> struct uic_command {
>> u32 command;
>> @@ -84,6 +86,7 @@ struct uic_command {
>> u32 argument3;
>> int cmd_active;
>> int result;
>> + struct completion done;
>> };
>>
>> /**
>> @@ -150,11 +153,11 @@ struct ufs_query {
>> * @ufs_version: UFS Version to which controller complies
>> * @irq: Irq number of the controller
>> * @active_uic_cmd: handle of active UIC command
>> + * @uic_cmd_mutex: mutex for uic command
>> * @ufshcd_tm_wait_queue: wait queue for task management
>> * @tm_condition: condition variable for task management
>> * @ufshcd_state: UFSHCD states
>> * @intr_mask: Interrupt Mask Bits
>> - * @uic_workq: Work queue for UIC completion handling
>> * @feh_workq: Work queue for fatal controller error handling
>> * @errors: HBA errors
>> * @query: query request information
>> @@ -186,7 +189,9 @@ struct ufs_hba {
>> u32 ufs_version;
>> unsigned int irq;
>>
>> - struct uic_command active_uic_cmd;
>> + struct uic_command *active_uic_cmd;
>> + struct mutex uic_cmd_mutex;
>> +
>> wait_queue_head_t ufshcd_tm_wait_queue;
>> unsigned long tm_condition;
>>
>> @@ -194,7 +199,6 @@ struct ufs_hba {
>> u32 intr_mask;
>>
>> /* Work Queues */
>> - struct work_struct uic_workq;
>> struct work_struct feh_workq;
>>
>> /* HBA Errors */
>>
>
> --
> Regards,
> Sujit
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations
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
1 sibling, 0 replies; 52+ messages in thread
From: merez @ 2013-05-06 10:37 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Hi James,
Can you please merge this patch on top of the query requests patch?
Thanks,
Maya
> Simplify operations with hiding mmio_base.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 105
> +++++++++++++++++++--------------------------
> drivers/scsi/ufs/ufshcd.h | 7 +++-
> 2 files changed, 50 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index f244812..cf7c8e4 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -71,7 +71,7 @@ enum {
> */
> static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UFS_VERSION);
> + return ufshcd_readl(hba, REG_UFS_VERSION);
> }
>
> /**
> @@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct
> ufs_hba *hba)
> */
> static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
> {
> - writel(~(1 << pos),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
> + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> }
>
> /**
> @@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
> */
> static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
> + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
> MASK_UIC_COMMAND_RESULT;
> }
>
> @@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int
> option)
> {
> switch (option) {
> case INT_AGGR_RESET:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_COUNTER_AND_TIMER_RESET),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE |
> + INT_AGGR_COUNTER_AND_TIMER_RESET,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> case INT_AGGR_CONFIG:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_PARAM_WRITE |
> - INT_AGGR_COUNTER_THRESHOLD_VALUE |
> - INT_AGGR_TIMEOUT_VALUE),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
> + INT_AGGR_COUNTER_THRESHOLD_VALUE |
> + INT_AGGR_TIMEOUT_VALUE,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> }
> }
> @@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int
> option)
> */
> static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> {
> - writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TASK_REQ_LIST_RUN_STOP));
> - writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
> + ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TASK_REQ_LIST_RUN_STOP);
> + ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
> }
>
> /**
> @@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba
> *hba)
> */
> static inline void ufshcd_hba_start(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
> }
>
> /**
> @@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba
> *hba)
> */
> static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
> {
> - return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> }
>
> /**
> @@ -299,8 +293,7 @@ static inline
> void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
> {
> __set_bit(task_tag, &hba->outstanding_reqs);
> - writel((1 << task_tag),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> }
>
> /**
> @@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
> */
> static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> {
> - hba->capabilities =
> - readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
> + hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
>
> /* nutrs and nutmrs are 0 based values */
> hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
> @@ -399,16 +391,13 @@ static inline void
> ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command
> *uic_cmnd)
> {
> /* Write Args */
> - writel(uic_cmnd->argument1,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
> - writel(uic_cmnd->argument2,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
> - writel(uic_cmnd->argument3,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
> + ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> + ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> + ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
>
> /* Write UIC Cmd */
> - writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
> - (hba->mmio_base + REG_UIC_COMMAND));
> + ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> + REG_UIC_COMMAND);
> }
>
> /**
> @@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba,
> u32 option)
> {
> switch (option) {
> case UFSHCD_INT_ENABLE:
> - writel(hba->int_enable_mask,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> break;
> case UFSHCD_INT_DISABLE:
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(INTERRUPT_DISABLE_MASK_10,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> + REG_INTERRUPT_ENABLE);
> else
> - writel(INTERRUPT_DISABLE_MASK_11,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> + REG_INTERRUPT_ENABLE);
> break;
> }
> }
> @@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba
> *hba)
> unsigned long flags;
>
> /* check if controller is ready to accept UIC commands */
> - if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
> + if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> UIC_COMMAND_READY) == 0x0) {
> dev_err(hba->dev,
> "Controller not ready"
> @@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba
> *hba)
> u32 reg;
>
> /* check if device present */
> - reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
> + reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
> if (!ufshcd_is_device_present(reg)) {
> dev_err(hba->dev, "cc: Device not present\n");
> err = -ENXIO;
> @@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba
> *hba)
> return -EIO;
>
> /* Configure UTRL and UTMRL base address registers */
> - writel(lower_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
> - writel(lower_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_H);
>
> /* Initialize unipro link startup procedure */
> return ufshcd_dme_link_startup(hba);
> @@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba
> *hba)
> int index;
>
> lrb = hba->lrb;
> - tr_doorbell =
> - readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
> + tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
>
> for (index = 0; index < hba->nutrs; index++) {
> @@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
> goto fatal_eh;
>
> if (hba->errors & UIC_ERROR) {
> -
> - reg = readl(hba->mmio_base +
> - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> goto fatal_eh;
> }
> @@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
> {
> u32 tm_doorbell;
>
> - tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
> + tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
> hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
> wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
> }
> @@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void
> *__hba)
> struct ufs_hba *hba = __hba;
>
> spin_lock(hba->host->host_lock);
> - intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
> + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
>
> if (intr_status) {
> ufshcd_sl_intr(hba, intr_status);
>
> /* If UFSHCI 1.0 then clear interrupt status register */
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(intr_status,
> - (hba->mmio_base + REG_INTERRUPT_STATUS));
> + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> retval = IRQ_HANDLED;
> }
> spin_unlock(hba->host->host_lock);
> @@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>
> /* send command to the controller */
> __set_bit(free_slot, &hba->outstanding_tasks);
> - writel((1 << free_slot),
> - (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
>
> spin_unlock_irqrestore(host->host_lock, flags);
>
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 336980b..6429bed 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -204,6 +204,11 @@ struct ufs_hba {
> struct ufs_query query;
> };
>
> +#define ufshcd_writel(hba, val, reg) \
> + writel((val), (hba)->mmio_base + (reg))
> +#define ufshcd_readl(hba, reg) \
> + readl((hba)->mmio_base + (reg))
> +
> int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
> @@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
> */
> static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> }
>
> #endif /* End of Header */
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3 2/6] scsi: ufs: amend interrupt configuration
2013-05-06 5:37 ` [PATCH v3 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
@ 2013-05-06 10:39 ` merez
0 siblings, 0 replies; 52+ messages in thread
From: merez @ 2013-05-06 10:39 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Hi James,
Can you please merge this patch?
Thanks,
Maya
> It makes interrupt setting more flexible especially
> for disabling. And wrong bit mask is fixed for ver 1.0.
> [17:16] is added for mask.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 84
> +++++++++++++++++++++++++++++++-------------
> drivers/scsi/ufs/ufshcd.h | 4 +-
> drivers/scsi/ufs/ufshci.h | 5 ++-
> 3 files changed, 64 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index cf7c8e4..feaf221 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -35,6 +35,10 @@
>
> #include "ufshcd.h"
>
> +#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
> + UTP_TASK_REQ_COMPL |\
> + UFSHCD_ERROR_MASK)
> +
> enum {
> UFSHCD_MAX_CHANNEL = 0,
> UFSHCD_MAX_ID = 1,
> @@ -64,6 +68,20 @@ enum {
> };
>
> /**
> + * ufshcd_get_intr_mask - Get the interrupt bit mask
> + * @hba - Pointer to adapter instance
> + *
> + * Returns interrupt bit mask per version
> + */
> +static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
> +{
> + if (hba->ufs_version == UFSHCI_VERSION_10)
> + return INTERRUPT_MASK_ALL_VER_10;
> + else
> + return INTERRUPT_MASK_ALL_VER_11;
> +}
> +
> +/**
> * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
> * @hba - Pointer to adapter instance
> *
> @@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
> }
>
> /**
> - * ufshcd_int_config - enable/disable interrupts
> + * ufshcd_enable_intr - enable interrupts
> * @hba: per adapter instance
> - * @option: interrupt option
> + * @intrs: interrupt bits
> */
> -static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
> +static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
> {
> - switch (option) {
> - case UFSHCD_INT_ENABLE:
> - ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> - break;
> - case UFSHCD_INT_DISABLE:
> - if (hba->ufs_version == UFSHCI_VERSION_10)
> - ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> - REG_INTERRUPT_ENABLE);
> - else
> - ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> - REG_INTERRUPT_ENABLE);
> - break;
> + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
> +
> + if (hba->ufs_version == UFSHCI_VERSION_10) {
> + u32 rw;
> + rw = set & INTERRUPT_MASK_RW_VER_10;
> + set = rw | ((set ^ intrs) & intrs);
> + } else {
> + set |= intrs;
> + }
> +
> + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
> +}
> +
> +/**
> + * ufshcd_disable_intr - disable interrupts
> + * @hba: per adapter instance
> + * @intrs: interrupt bits
> + */
> +static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
> +{
> + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
> +
> + if (hba->ufs_version == UFSHCI_VERSION_10) {
> + u32 rw;
> + rw = (set & INTERRUPT_MASK_RW_VER_10) &
> + ~(intrs & INTERRUPT_MASK_RW_VER_10);
> + set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
> +
> + } else {
> + set &= ~intrs;
> }
> +
> + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
> }
>
> /**
> @@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba
> *hba)
> uic_cmd->argument3 = 0;
>
> /* enable UIC related interrupts */
> - hba->int_enable_mask |= UIC_COMMAND_COMPL;
> - ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
> + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>
> /* sending UIC commands to controller */
> ufshcd_send_uic_command(hba, uic_cmd);
> @@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct
> ufs_hba *hba)
> }
>
> /* Enable required interrupts */
> - hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
> - UIC_ERROR |
> - UTP_TASK_REQ_COMPL |
> - DEVICE_FATAL_ERROR |
> - CONTROLLER_FATAL_ERROR |
> - SYSTEM_BUS_FATAL_ERROR);
> - ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
> + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
>
> /* Configure interrupt aggregation */
> ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> @@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
> void ufshcd_remove(struct ufs_hba *hba)
> {
> /* disable interrupts */
> - ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
> + ufshcd_disable_intr(hba, hba->intr_mask);
>
> ufshcd_hba_stop(hba);
> ufshcd_hba_free(hba);
> @@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba
> **hba_handle,
> /* Get UFS version supported by the controller */
> hba->ufs_version = ufshcd_get_ufs_version(hba);
>
> + /* Get Interrupt bit mask per version */
> + hba->intr_mask = ufshcd_get_intr_mask(hba);
> +
> /* Allocate memory for host memory space */
> err = ufshcd_memory_alloc(hba);
> if (err) {
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 6429bed..d98e046 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -153,7 +153,7 @@ struct ufs_query {
> * @ufshcd_tm_wait_queue: wait queue for task management
> * @tm_condition: condition variable for task management
> * @ufshcd_state: UFSHCD states
> - * @int_enable_mask: Interrupt Mask Bits
> + * @intr_mask: Interrupt Mask Bits
> * @uic_workq: Work queue for UIC completion handling
> * @feh_workq: Work queue for fatal controller error handling
> * @errors: HBA errors
> @@ -191,7 +191,7 @@ struct ufs_hba {
> unsigned long tm_condition;
>
> u32 ufshcd_state;
> - u32 int_enable_mask;
> + u32 intr_mask;
>
> /* Work Queues */
> struct work_struct uic_workq;
> diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
> index 4a86247..f1e1b74 100644
> --- a/drivers/scsi/ufs/ufshci.h
> +++ b/drivers/scsi/ufs/ufshci.h
> @@ -232,10 +232,11 @@ enum {
> /* Interrupt disable masks */
> enum {
> /* Interrupt disable mask for UFSHCI v1.0 */
> - INTERRUPT_DISABLE_MASK_10 = 0xFFFF,
> + INTERRUPT_MASK_ALL_VER_10 = 0x30FFF,
> + INTERRUPT_MASK_RW_VER_10 = 0x30000,
>
> /* Interrupt disable mask for UFSHCI v1.1 */
> - INTERRUPT_DISABLE_MASK_11 = 0x0,
> + INTERRUPT_MASK_ALL_VER_11 = 0x31FFF,
> };
>
> /*
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3 3/6] scsi: ufs: fix interrupt status clears
2013-05-06 5:37 ` [PATCH v3 3/6] scsi: ufs: fix interrupt status clears Seungwon Jeon
@ 2013-05-06 10:49 ` merez
0 siblings, 0 replies; 52+ messages in thread
From: merez @ 2013-05-06 10:49 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Tested-by: Maya Erez <merez@codeaurora.org>
> There is no need to check the version to clear
> the interrupt status. And the order is changed
> prior to actual handling.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> drivers/scsi/ufs/ufshcd.c | 5 +----
> 1 files changed, 1 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index feaf221..e04c74e 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -1582,11 +1582,8 @@ static irqreturn_t ufshcd_intr(int irq, void
> *__hba)
> intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
>
> if (intr_status) {
> + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> ufshcd_sl_intr(hba, intr_status);
> -
> - /* If UFSHCI 1.0 then clear interrupt status register */
> - if (hba->ufs_version == UFSHCI_VERSION_10)
> - ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> retval = IRQ_HANDLED;
> }
> spin_unlock(hba->host->host_lock);
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v3 4/6] scsi: ufs: rework link start-up process
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
1 sibling, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-06 11:21 UTC (permalink / raw)
To: 'Sujit Reddy Thumma'
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
On Monday, May 06, 2013, Sujit Reddy Thumma wrote:
> On 5/6/2013 11:07 AM, Seungwon Jeon wrote:
> > Link start-up requires long time with multiphase handshakes
> > between UFS host and device. This affects driver's probe time.
> > This patch let link start-up run asynchronously. Link start-up
> > will be executed at the end of prove separately.
> > Along with this change, the following is worked.
> >
> > Defined completion time of uic command to avoid a permanent wait.
> We have seen a kernel crash when the timeout happens in our internal
> testing. This is basically because the the UIC_CMD_TIMEOUT of 500msec is
> less for our platform. We see UIC_COMMAND_COMPL interrupt after this
> timeout and since uic_cmd is freed we see a kernel crash.
>
> [ 6.026094] ufshcd 0000:01:00.0: link startup: error code -110
> [ 6.030886] ufshcd 0000:01:00.0: link startup failed -110
> ...
>
> [ 6.487288] BUG: spinlock bad magic on CPU#0, swapper/0/0
> [ 6.491683] Unable to handle kernel paging request at virtual address
> 6000012b
> ...
> [ 7.625270] [<c07c3718>] (spin_dump+0x4c/0x88) from [<c02ab9d8>]
> (do_raw_spin_lock+0x20/0x154)
> [ 7.633877] [<c02ab9d8>] (do_raw_spin_lock+0x20/0x154) from
> [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30)
> [ 7.643583] [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30) from
> [<c00a3c98>] (complete+0x1c/0x58)
> [ 7.652525] [<c00a3c98>] (complete+0x1c/0x58) from [<c03d10c4>]
> (ufshcd_intr+0x1a8/0x498)
> [ 7.660705] [<c03d10c4>] (ufshcd_intr+0x1a8/0x498) from [<c00cff48>]
> (handle_irq_event_percpu+0xb0/0x290)
> [ 7.670227] [<c00cff48>] (handle_irq_event_percpu+0xb0/0x290) from
> [<c00d0164>] (handle_irq_event+0x3c/0x5c)
> [ 7.680054] [<c00d0164>] (handle_irq_event+0x3c/0x5c) from
> [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148)
> [ 7.689424] [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148) from
> [<c00cf7ac>] (generic_handle_irq+0x30/0x44)
> [ 7.698977] [<c00cf7ac>] (generic_handle_irq+0x30/0x44) from
> [<c000ee40>] (handle_IRQ+0x7c/0xc0)
> [ 7.707736] [<c000ee40>] (handle_IRQ+0x7c/0xc0) from [<c0008620>]
> (gic_handle_irq+0x94/0x110)
> [ 7.716252] [<c0008620>] (gic_handle_irq+0x94/0x110) from
> [<c07ccec0>] (__irq_svc+0x40/0x70)
>
>
> Following would fix this. Please check. Also, we need to increase the
> timeout to say 5 secs to avoid such races.
Thank you for test.
I have seen the completion of link startup within current timeout ever.
It should be fixed for that case.
By the way, I feel 5 seconds looks like a little too long.
Currently, is your platform situation with UFS in normal stage?
The UNIPRO spec. mentions the 100 ms as timeout internally for link startup.
Anyway, do you mean that you want to change timeout value to 5 seconds?
I think it has a strong dependency with your platform.
1 sec seems proper though the worst case is considered.
Thanks,
Seungwon Jeon
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index ecbae40..ae22a8e 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -485,6 +485,7 @@ static int
> ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> {
> int ret;
> + unsigned long flags;
>
> if (wait_for_completion_timeout(&uic_cmd->done,
> msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> @@ -492,6 +493,10 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct
> uic_command *uic_cmd)
> else
> ret = -ETIMEDOUT;
>
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + hba->active_uic_cmd = NULL;
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> return ret;
> }
>
> @@ -1842,7 +1847,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
> */
> static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
> {
> - if (intr_status & UIC_COMMAND_COMPL) {
> + if (hba->active_uic_cmd && (intr_status & UIC_COMMAND_COMPL)) {
> hba->active_uic_cmd->argument2 |=
> ufshcd_get_uic_cmd_result(hba);
> hba->active_uic_cmd->argument3 =
>
>
> > Added mutex to guarantee of uic command at a time.
> > Adapted some sequence of controller initialization after link statup
> > according to HCI standard.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
> > ---
> > drivers/scsi/ufs/ufshcd.c | 287 ++++++++++++++++++++++++++++++---------------
> > drivers/scsi/ufs/ufshcd.h | 10 +-
> > 2 files changed, 200 insertions(+), 97 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index e04c74e..118f104 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -33,11 +33,15 @@
> > * this program.
> > */
> >
> > +#include <linux/async.h>
> > +
> > #include "ufshcd.h"
> >
> > #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
> > UTP_TASK_REQ_COMPL |\
> > UFSHCD_ERROR_MASK)
> > +/* UIC command timeout, unit: ms */
> > +#define UIC_CMD_TIMEOUT 500
> >
> > enum {
> > UFSHCD_MAX_CHANNEL = 0,
> > @@ -401,24 +405,115 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> > }
> >
> > /**
> > - * ufshcd_send_uic_command - Send UIC commands to unipro layers
> > + * ufshcd_ready_for_uic_cmd - Check if controller is ready
> > + * to accept UIC commands
> > * @hba: per adapter instance
> > - * @uic_command: UIC command
> > + * Return true on success, else false
> > + */
> > +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
> > +{
> > + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
> > + return true;
> > + else
> > + return false;
> > +}
> > +
> > +/**
> > + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> > + * @hba: per adapter instance
> > + * @uic_cmd: UIC command
> > + *
> > + * Mutex must be held.
> > */
> > static inline void
> > -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> > +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> > {
> > + hba->active_uic_cmd = uic_cmd;
> > +
> > /* Write Args */
> > - ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> > - ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> > - ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
> > + ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
> > + ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
> > + ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
> >
> > /* Write UIC Cmd */
> > - ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> > + ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
> > REG_UIC_COMMAND);
> > }
> >
> > /**
> > + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
> > + * @hba: per adapter instance
> > + * @uic_command: UIC command
> > + *
> > + * Must be called with mutex held.
> > + * Returns 0 only if success.
> > + */
> > +static int
> > +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> > +{
> > + int ret;
> > +
> > + if (wait_for_completion_timeout(&uic_cmd->done,
> > + msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> > + ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
> > + else
> > + ret = -ETIMEDOUT;
> > +
> > + return ret;
> > +}
> > +
> > +/**
> > + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
> > + * @hba: per adapter instance
> > + * @uic_cmd: UIC command
> > + *
> > + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
> > + * with mutex held.
> > + * Returns 0 only if success.
> > + */
> > +static int
> > +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> > +{
> > + int ret;
> > + unsigned long flags;
> > +
> > + if (!ufshcd_ready_for_uic_cmd(hba)) {
> > + dev_err(hba->dev,
> > + "Controller not ready to accept UIC commands\n");
> > + return -EIO;
> > + }
> > +
> > + init_completion(&uic_cmd->done);
> > +
> > + spin_lock_irqsave(hba->host->host_lock, flags);
> > + ufshcd_dispatch_uic_cmd(hba, uic_cmd);
> > + spin_unlock_irqrestore(hba->host->host_lock, flags);
> > +
> > + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
> > +
> > + return ret;
> > +}
> > +
> > +/**
> > + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
> > + * @hba: per adapter instance
> > + * @uic_cmd: UIC command
> > + *
> > + * Returns 0 only if success.
> > + */
> > +static int
> > +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> > +{
> > + int ret;
> > +
> > + mutex_lock(&hba->uic_cmd_mutex);
> > + ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
> > + mutex_unlock(&hba->uic_cmd_mutex);
> > +
> > + return ret;
> > +}
> > +
> > +/**
> > * ufshcd_map_sg - Map scatter-gather list to prdt
> > * @lrbp - pointer to local reference block
> > *
> > @@ -962,34 +1057,16 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
> > */
> > static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> > {
> > - struct uic_command *uic_cmd;
> > - unsigned long flags;
> > + struct uic_command uic_cmd = {0};
> > + int ret;
> >
> > - /* check if controller is ready to accept UIC commands */
> > - if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> > - UIC_COMMAND_READY) == 0x0) {
> > - dev_err(hba->dev,
> > - "Controller not ready"
> > - " to accept UIC commands\n");
> > - return -EIO;
> > - }
> > -
> > - spin_lock_irqsave(hba->host->host_lock, flags);
> > + uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
> >
> > - /* form UIC command */
> > - uic_cmd = &hba->active_uic_cmd;
> > - uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
> > - uic_cmd->argument1 = 0;
> > - uic_cmd->argument2 = 0;
> > - uic_cmd->argument3 = 0;
> > -
> > - /* enable UIC related interrupts */
> > - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
> > -
> > - /* sending UIC commands to controller */
> > - ufshcd_send_uic_command(hba, uic_cmd);
> > - spin_unlock_irqrestore(hba->host->host_lock, flags);
> > - return 0;
> > + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> > + if (ret)
> > + dev_err(hba->dev,
> > + "link startup: error code %d\n", ret);
> > + return ret;
> > }
> >
> > /**
> > @@ -998,9 +1075,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> > *
> > * To bring UFS host controller to operational state,
> > * 1. Check if device is present
> > - * 2. Configure run-stop-registers
> > - * 3. Enable required interrupts
> > - * 4. Configure interrupt aggregation
> > + * 2. Enable required interrupts
> > + * 3. Configure interrupt aggregation
> > + * 4. Program UTRL and UTMRL base addres
> > + * 5. Configure run-stop-registers
> > *
> > * Returns 0 on success, non-zero value on failure
> > */
> > @@ -1017,6 +1095,22 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> > goto out;
> > }
> >
> > + /* Enable required interrupts */
> > + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
> > +
> > + /* Configure interrupt aggregation */
> > + ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> > +
> > + /* Configure UTRL and UTMRL base address registers */
> > + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> > + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> > + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> > + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> > + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> > + REG_UTP_TASK_REQ_LIST_BASE_L);
> > + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> > + REG_UTP_TASK_REQ_LIST_BASE_H);
> > +
> > /*
> > * UCRDY, UTMRLDY and UTRLRDY bits must be 1
> > * DEI, HEI bits must be 0
> > @@ -1030,17 +1124,11 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> > goto out;
> > }
> >
> > - /* Enable required interrupts */
> > - ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
> > -
> > - /* Configure interrupt aggregation */
> > - ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> > -
> > if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> > scsi_unblock_requests(hba->host);
> >
> > hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
> > - scsi_scan_host(hba->host);
> > +
> > out:
> > return err;
> > }
> > @@ -1109,34 +1197,29 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
> > }
> >
> > /**
> > - * ufshcd_initialize_hba - start the initialization process
> > + * ufshcd_link_startup - Initialize unipro link startup
> > * @hba: per adapter instance
> > *
> > - * 1. Enable the controller via ufshcd_hba_enable.
> > - * 2. Program the Transfer Request List Address with the starting address of
> > - * UTRDL.
> > - * 3. Program the Task Management Request List Address with starting address
> > - * of UTMRDL.
> > - *
> > - * Returns 0 on success, non-zero value on failure.
> > + * Returns 0 for success, non-zero in case of failure
> > */
> > -static int ufshcd_initialize_hba(struct ufs_hba *hba)
> > +static int ufshcd_link_startup(struct ufs_hba *hba)
> > {
> > - if (ufshcd_hba_enable(hba))
> > - return -EIO;
> > + int ret;
> >
> > - /* Configure UTRL and UTMRL base address registers */
> > - ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> > - REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> > - ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> > - REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> > - ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> > - REG_UTP_TASK_REQ_LIST_BASE_L);
> > - ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> > - REG_UTP_TASK_REQ_LIST_BASE_H);
> > + /* enable UIC related interrupts */
> > + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
> > +
> > + ret = ufshcd_dme_link_startup(hba);
> > + if (ret)
> > + goto out;
> >
> > - /* Initialize unipro link startup procedure */
> > - return ufshcd_dme_link_startup(hba);
> > + ret = ufshcd_make_hba_operational(hba);
> > + if (ret)
> > + goto out;
> > +
> > +out:
> > + dev_err(hba->dev, "link startup failed %d\n", ret);
> > + return ret;
> > }
> >
> > /**
> > @@ -1176,12 +1259,19 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
> > hba->outstanding_reqs = 0;
> > hba->outstanding_tasks = 0;
> >
> > - /* start the initialization process */
> > - if (ufshcd_initialize_hba(hba)) {
> > + /* Host controller enable */
> > + if (ufshcd_hba_enable(hba)) {
> > dev_err(hba->dev,
> > "Reset: Controller initialization failed\n");
> > return FAILED;
> > }
> > +
> > + if (ufshcd_link_startup(hba)) {
> > + dev_err(hba->dev,
> > + "Reset: Link start-up failed\n");
> > + return FAILED;
> > + }
> > +
> > return SUCCESS;
> > }
> >
> > @@ -1434,6 +1524,17 @@ 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
> > + */
> > +static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
> > +{
> > + hba->active_uic_cmd->argument2 |=
> > + ufshcd_get_uic_cmd_result(hba);
> > + complete(&hba->active_uic_cmd->done);
> > +}
> > +
> > +/**
> > * ufshcd_transfer_req_compl - handle SCSI and query command completion
> > * @hba: per adapter instance
> > */
> > @@ -1473,28 +1574,6 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
> > }
> >
> > /**
> > - * ufshcd_uic_cc_handler - handle UIC command completion
> > - * @work: pointer to a work queue structure
> > - *
> > - * Returns 0 on success, non-zero value on failure
> > - */
> > -static void ufshcd_uic_cc_handler (struct work_struct *work)
> > -{
> > - struct ufs_hba *hba;
> > -
> > - hba = container_of(work, struct ufs_hba, uic_workq);
> > -
> > - if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
> > - !(ufshcd_get_uic_cmd_result(hba))) {
> > -
> > - if (ufshcd_make_hba_operational(hba))
> > - dev_err(hba->dev,
> > - "cc: hba not operational state\n");
> > - return;
> > - }
> > -}
> > -
> > -/**
> > * ufshcd_fatal_err_handler - handle fatal errors
> > * @hba: per adapter instance
> > */
> > @@ -1555,7 +1634,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
> > ufshcd_err_handler(hba);
> >
> > if (intr_status & UIC_COMMAND_COMPL)
> > - schedule_work(&hba->uic_workq);
> > + ufshcd_uic_cmd_compl(hba);
> >
> > if (intr_status & UTP_TASK_REQ_COMPL)
> > ufshcd_tmc_handler(hba);
> > @@ -1778,6 +1857,21 @@ out:
> > return err;
> > }
> >
> > +/**
> > + * ufshcd_async_scan - asynchronous execution for link startup
> > + * @data: data pointer to pass to this function
> > + * @cookie: cookie data
> > + */
> > +static void ufshcd_async_scan(void *data, async_cookie_t cookie)
> > +{
> > + struct ufs_hba *hba = (struct ufs_hba *)data;
> > + int ret;
> > +
> > + ret = ufshcd_link_startup(hba);
> > + if (!ret)
> > + scsi_scan_host(hba->host);
> > +}
> > +
> > static struct scsi_host_template ufshcd_driver_template = {
> > .module = THIS_MODULE,
> > .name = UFSHCD,
> > @@ -1939,12 +2033,14 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> > init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
> >
> > /* Initialize work queues */
> > - INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
> > INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
> >
> > /* Initialize mutex for query requests */
> > mutex_init(&hba->query.lock_ufs_query);
> >
> > + /* Initialize UIC command mutex */
> > + mutex_init(&hba->uic_cmd_mutex);
> > +
> > /* IRQ registration */
> > err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
> > if (err) {
> > @@ -1965,14 +2061,17 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> > goto out_free_irq;
> > }
> >
> > - /* Initialization routine */
> > - err = ufshcd_initialize_hba(hba);
> > + /* Host controller enable */
> > + err = ufshcd_hba_enable(hba);
> > if (err) {
> > - dev_err(hba->dev, "Initialization failed\n");
> > + dev_err(hba->dev, "Host controller enable failed\n");
> > goto out_remove_scsi_host;
> > }
> > +
> > *hba_handle = hba;
> >
> > + async_schedule(ufshcd_async_scan, hba);
> > +
> > return 0;
> >
> > out_remove_scsi_host:
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index d98e046..974bd07 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -51,6 +51,7 @@
> > #include <linux/bitops.h>
> > #include <linux/pm_runtime.h>
> > #include <linux/clk.h>
> > +#include <linux/completion.h>
> >
> > #include <asm/irq.h>
> > #include <asm/byteorder.h>
> > @@ -76,6 +77,7 @@
> > * @argument3: UIC command argument 3
> > * @cmd_active: Indicate if UIC command is outstanding
> > * @result: UIC command result
> > + * @done: UIC command completion
> > */
> > struct uic_command {
> > u32 command;
> > @@ -84,6 +86,7 @@ struct uic_command {
> > u32 argument3;
> > int cmd_active;
> > int result;
> > + struct completion done;
> > };
> >
> > /**
> > @@ -150,11 +153,11 @@ struct ufs_query {
> > * @ufs_version: UFS Version to which controller complies
> > * @irq: Irq number of the controller
> > * @active_uic_cmd: handle of active UIC command
> > + * @uic_cmd_mutex: mutex for uic command
> > * @ufshcd_tm_wait_queue: wait queue for task management
> > * @tm_condition: condition variable for task management
> > * @ufshcd_state: UFSHCD states
> > * @intr_mask: Interrupt Mask Bits
> > - * @uic_workq: Work queue for UIC completion handling
> > * @feh_workq: Work queue for fatal controller error handling
> > * @errors: HBA errors
> > * @query: query request information
> > @@ -186,7 +189,9 @@ struct ufs_hba {
> > u32 ufs_version;
> > unsigned int irq;
> >
> > - struct uic_command active_uic_cmd;
> > + struct uic_command *active_uic_cmd;
> > + struct mutex uic_cmd_mutex;
> > +
> > wait_queue_head_t ufshcd_tm_wait_queue;
> > unsigned long tm_condition;
> >
> > @@ -194,7 +199,6 @@ struct ufs_hba {
> > u32 intr_mask;
> >
> > /* Work Queues */
> > - struct work_struct uic_workq;
> > struct work_struct feh_workq;
> >
> > /* HBA Errors */
> >
>
> --
> Regards,
> Sujit
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v3 4/6] scsi: ufs: rework link start-up process
2013-05-06 11:21 ` Seungwon Jeon
@ 2013-05-06 18:15 ` merez
0 siblings, 0 replies; 52+ messages in thread
From: merez @ 2013-05-06 18:15 UTC (permalink / raw)
To: Seungwon Jeon
Cc: 'Sujit Reddy Thumma', linux-scsi,
'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
> On Monday, May 06, 2013, Sujit Reddy Thumma wrote:
>> On 5/6/2013 11:07 AM, Seungwon Jeon wrote:
>> > Link start-up requires long time with multiphase handshakes
>> > between UFS host and device. This affects driver's probe time.
>> > This patch let link start-up run asynchronously. Link start-up
>> > will be executed at the end of prove separately.
>> > Along with this change, the following is worked.
>> >
>> > Defined completion time of uic command to avoid a permanent wait.
>> We have seen a kernel crash when the timeout happens in our internal
>> testing. This is basically because the the UIC_CMD_TIMEOUT of 500msec is
>> less for our platform. We see UIC_COMMAND_COMPL interrupt after this
>> timeout and since uic_cmd is freed we see a kernel crash.
>>
>> [ 6.026094] ufshcd 0000:01:00.0: link startup: error code -110
>> [ 6.030886] ufshcd 0000:01:00.0: link startup failed -110
>> ...
>>
>> [ 6.487288] BUG: spinlock bad magic on CPU#0, swapper/0/0
>> [ 6.491683] Unable to handle kernel paging request at virtual address
>> 6000012b
>> ...
>> [ 7.625270] [<c07c3718>] (spin_dump+0x4c/0x88) from [<c02ab9d8>]
>> (do_raw_spin_lock+0x20/0x154)
>> [ 7.633877] [<c02ab9d8>] (do_raw_spin_lock+0x20/0x154) from
>> [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30)
>> [ 7.643583] [<c07ccba4>] (_raw_spin_lock_irqsave+0x28/0x30) from
>> [<c00a3c98>] (complete+0x1c/0x58)
>> [ 7.652525] [<c00a3c98>] (complete+0x1c/0x58) from [<c03d10c4>]
>> (ufshcd_intr+0x1a8/0x498)
>> [ 7.660705] [<c03d10c4>] (ufshcd_intr+0x1a8/0x498) from [<c00cff48>]
>> (handle_irq_event_percpu+0xb0/0x290)
>> [ 7.670227] [<c00cff48>] (handle_irq_event_percpu+0xb0/0x290) from
>> [<c00d0164>] (handle_irq_event+0x3c/0x5c)
>> [ 7.680054] [<c00d0164>] (handle_irq_event+0x3c/0x5c) from
>> [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148)
>> [ 7.689424] [<c00d2c50>] (handle_fasteoi_irq+0xdc/0x148) from
>> [<c00cf7ac>] (generic_handle_irq+0x30/0x44)
>> [ 7.698977] [<c00cf7ac>] (generic_handle_irq+0x30/0x44) from
>> [<c000ee40>] (handle_IRQ+0x7c/0xc0)
>> [ 7.707736] [<c000ee40>] (handle_IRQ+0x7c/0xc0) from [<c0008620>]
>> (gic_handle_irq+0x94/0x110)
>> [ 7.716252] [<c0008620>] (gic_handle_irq+0x94/0x110) from
>> [<c07ccec0>] (__irq_svc+0x40/0x70)
>>
>>
>> Following would fix this. Please check. Also, we need to increase the
>> timeout to say 5 secs to avoid such races.
> Thank you for test.
> I have seen the completion of link startup within current timeout ever.
> It should be fixed for that case.
> By the way, I feel 5 seconds looks like a little too long.
> Currently, is your platform situation with UFS in normal stage?
> The UNIPRO spec. mentions the 100 ms as timeout internally for link
> startup.
> Anyway, do you mean that you want to change timeout value to 5 seconds?
> I think it has a strong dependency with your platform.
> 1 sec seems proper though the worst case is considered.
>
> Thanks,
> Seungwon Jeon
I agree, you can keep a timeout of 500ms. I got the timeout due to a
unipro issue and not due to low timeout value.
Thanks,
Maya
>
>>
>> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> index ecbae40..ae22a8e 100644
>> --- a/drivers/scsi/ufs/ufshcd.c
>> +++ b/drivers/scsi/ufs/ufshcd.c
>> @@ -485,6 +485,7 @@ static int
>> ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command
>> *uic_cmd)
>> {
>> int ret;
>> + unsigned long flags;
>>
>> if (wait_for_completion_timeout(&uic_cmd->done,
>> msecs_to_jiffies(UIC_CMD_TIMEOUT)))
>> @@ -492,6 +493,10 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct
>> uic_command *uic_cmd)
>> else
>> ret = -ETIMEDOUT;
>>
>> + spin_lock_irqsave(hba->host->host_lock, flags);
>> + hba->active_uic_cmd = NULL;
>> + spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> return ret;
>> }
>>
>> @@ -1842,7 +1847,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba,
>> struct ufshcd_lrb *lrbp)
>> */
>> static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
>> {
>> - if (intr_status & UIC_COMMAND_COMPL) {
>> + if (hba->active_uic_cmd && (intr_status & UIC_COMMAND_COMPL)) {
>> hba->active_uic_cmd->argument2 |=
>> ufshcd_get_uic_cmd_result(hba);
>> hba->active_uic_cmd->argument3 =
>>
>>
>> > Added mutex to guarantee of uic command at a time.
>> > Adapted some sequence of controller initialization after link statup
>> > according to HCI standard.
>> >
>> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> > Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
>> > ---
>> > drivers/scsi/ufs/ufshcd.c | 287
>> ++++++++++++++++++++++++++++++---------------
>> > drivers/scsi/ufs/ufshcd.h | 10 +-
>> > 2 files changed, 200 insertions(+), 97 deletions(-)
>> >
>> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
>> > index e04c74e..118f104 100644
>> > --- a/drivers/scsi/ufs/ufshcd.c
>> > +++ b/drivers/scsi/ufs/ufshcd.c
>> > @@ -33,11 +33,15 @@
>> > * this program.
>> > */
>> >
>> > +#include <linux/async.h>
>> > +
>> > #include "ufshcd.h"
>> >
>> > #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
>> > UTP_TASK_REQ_COMPL |\
>> > UFSHCD_ERROR_MASK)
>> > +/* UIC command timeout, unit: ms */
>> > +#define UIC_CMD_TIMEOUT 500
>> >
>> > enum {
>> > UFSHCD_MAX_CHANNEL = 0,
>> > @@ -401,24 +405,115 @@ static inline void
>> ufshcd_hba_capabilities(struct ufs_hba *hba)
>> > }
>> >
>> > /**
>> > - * ufshcd_send_uic_command - Send UIC commands to unipro layers
>> > + * ufshcd_ready_for_uic_cmd - Check if controller is ready
>> > + * to accept UIC commands
>> > * @hba: per adapter instance
>> > - * @uic_command: UIC command
>> > + * Return true on success, else false
>> > + */
>> > +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
>> > +{
>> > + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
>> > + return true;
>> > + else
>> > + return false;
>> > +}
>> > +
>> > +/**
>> > + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
>> > + * @hba: per adapter instance
>> > + * @uic_cmd: UIC command
>> > + *
>> > + * Mutex must be held.
>> > */
>> > static inline void
>> > -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command
>> *uic_cmnd)
>> > +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command
>> *uic_cmd)
>> > {
>> > + hba->active_uic_cmd = uic_cmd;
>> > +
>> > /* Write Args */
>> > - ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
>> > - ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
>> > - ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
>> > + ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
>> > + ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
>> > + ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
>> >
>> > /* Write UIC Cmd */
>> > - ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
>> > + ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
>> > REG_UIC_COMMAND);
>> > }
>> >
>> > /**
>> > + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
>> > + * @hba: per adapter instance
>> > + * @uic_command: UIC command
>> > + *
>> > + * Must be called with mutex held.
>> > + * Returns 0 only if success.
>> > + */
>> > +static int
>> > +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command
>> *uic_cmd)
>> > +{
>> > + int ret;
>> > +
>> > + if (wait_for_completion_timeout(&uic_cmd->done,
>> > + msecs_to_jiffies(UIC_CMD_TIMEOUT)))
>> > + ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
>> > + else
>> > + ret = -ETIMEDOUT;
>> > +
>> > + return ret;
>> > +}
>> > +
>> > +/**
>> > + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
>> > + * @hba: per adapter instance
>> > + * @uic_cmd: UIC command
>> > + *
>> > + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
>> > + * with mutex held.
>> > + * Returns 0 only if success.
>> > + */
>> > +static int
>> > +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command
>> *uic_cmd)
>> > +{
>> > + int ret;
>> > + unsigned long flags;
>> > +
>> > + if (!ufshcd_ready_for_uic_cmd(hba)) {
>> > + dev_err(hba->dev,
>> > + "Controller not ready to accept UIC commands\n");
>> > + return -EIO;
>> > + }
>> > +
>> > + init_completion(&uic_cmd->done);
>> > +
>> > + spin_lock_irqsave(hba->host->host_lock, flags);
>> > + ufshcd_dispatch_uic_cmd(hba, uic_cmd);
>> > + spin_unlock_irqrestore(hba->host->host_lock, flags);
>> > +
>> > + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
>> > +
>> > + return ret;
>> > +}
>> > +
>> > +/**
>> > + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
>> > + * @hba: per adapter instance
>> > + * @uic_cmd: UIC command
>> > + *
>> > + * Returns 0 only if success.
>> > + */
>> > +static int
>> > +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
>> > +{
>> > + int ret;
>> > +
>> > + mutex_lock(&hba->uic_cmd_mutex);
>> > + ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
>> > + mutex_unlock(&hba->uic_cmd_mutex);
>> > +
>> > + return ret;
>> > +}
>> > +
>> > +/**
>> > * ufshcd_map_sg - Map scatter-gather list to prdt
>> > * @lrbp - pointer to local reference block
>> > *
>> > @@ -962,34 +1057,16 @@ static void ufshcd_host_memory_configure(struct
>> ufs_hba *hba)
>> > */
>> > static int ufshcd_dme_link_startup(struct ufs_hba *hba)
>> > {
>> > - struct uic_command *uic_cmd;
>> > - unsigned long flags;
>> > + struct uic_command uic_cmd = {0};
>> > + int ret;
>> >
>> > - /* check if controller is ready to accept UIC commands */
>> > - if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
>> > - UIC_COMMAND_READY) == 0x0) {
>> > - dev_err(hba->dev,
>> > - "Controller not ready"
>> > - " to accept UIC commands\n");
>> > - return -EIO;
>> > - }
>> > -
>> > - spin_lock_irqsave(hba->host->host_lock, flags);
>> > + uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
>> >
>> > - /* form UIC command */
>> > - uic_cmd = &hba->active_uic_cmd;
>> > - uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
>> > - uic_cmd->argument1 = 0;
>> > - uic_cmd->argument2 = 0;
>> > - uic_cmd->argument3 = 0;
>> > -
>> > - /* enable UIC related interrupts */
>> > - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>> > -
>> > - /* sending UIC commands to controller */
>> > - ufshcd_send_uic_command(hba, uic_cmd);
>> > - spin_unlock_irqrestore(hba->host->host_lock, flags);
>> > - return 0;
>> > + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
>> > + if (ret)
>> > + dev_err(hba->dev,
>> > + "link startup: error code %d\n", ret);
>> > + return ret;
>> > }
>> >
>> > /**
>> > @@ -998,9 +1075,10 @@ static int ufshcd_dme_link_startup(struct
>> ufs_hba *hba)
>> > *
>> > * To bring UFS host controller to operational state,
>> > * 1. Check if device is present
>> > - * 2. Configure run-stop-registers
>> > - * 3. Enable required interrupts
>> > - * 4. Configure interrupt aggregation
>> > + * 2. Enable required interrupts
>> > + * 3. Configure interrupt aggregation
>> > + * 4. Program UTRL and UTMRL base addres
>> > + * 5. Configure run-stop-registers
>> > *
>> > * Returns 0 on success, non-zero value on failure
>> > */
>> > @@ -1017,6 +1095,22 @@ static int ufshcd_make_hba_operational(struct
>> ufs_hba *hba)
>> > goto out;
>> > }
>> >
>> > + /* Enable required interrupts */
>> > + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
>> > +
>> > + /* Configure interrupt aggregation */
>> > + ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
>> > +
>> > + /* Configure UTRL and UTMRL base address registers */
>> > + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
>> > + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
>> > + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
>> > + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
>> > + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
>> > + REG_UTP_TASK_REQ_LIST_BASE_L);
>> > + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
>> > + REG_UTP_TASK_REQ_LIST_BASE_H);
>> > +
>> > /*
>> > * UCRDY, UTMRLDY and UTRLRDY bits must be 1
>> > * DEI, HEI bits must be 0
>> > @@ -1030,17 +1124,11 @@ static int ufshcd_make_hba_operational(struct
>> ufs_hba *hba)
>> > goto out;
>> > }
>> >
>> > - /* Enable required interrupts */
>> > - ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
>> > -
>> > - /* Configure interrupt aggregation */
>> > - ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
>> > -
>> > if (hba->ufshcd_state == UFSHCD_STATE_RESET)
>> > scsi_unblock_requests(hba->host);
>> >
>> > hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
>> > - scsi_scan_host(hba->host);
>> > +
>> > out:
>> > return err;
>> > }
>> > @@ -1109,34 +1197,29 @@ static int ufshcd_hba_enable(struct ufs_hba
>> *hba)
>> > }
>> >
>> > /**
>> > - * ufshcd_initialize_hba - start the initialization process
>> > + * ufshcd_link_startup - Initialize unipro link startup
>> > * @hba: per adapter instance
>> > *
>> > - * 1. Enable the controller via ufshcd_hba_enable.
>> > - * 2. Program the Transfer Request List Address with the starting
>> address of
>> > - * UTRDL.
>> > - * 3. Program the Task Management Request List Address with starting
>> address
>> > - * of UTMRDL.
>> > - *
>> > - * Returns 0 on success, non-zero value on failure.
>> > + * Returns 0 for success, non-zero in case of failure
>> > */
>> > -static int ufshcd_initialize_hba(struct ufs_hba *hba)
>> > +static int ufshcd_link_startup(struct ufs_hba *hba)
>> > {
>> > - if (ufshcd_hba_enable(hba))
>> > - return -EIO;
>> > + int ret;
>> >
>> > - /* Configure UTRL and UTMRL base address registers */
>> > - ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
>> > - REG_UTP_TRANSFER_REQ_LIST_BASE_L);
>> > - ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
>> > - REG_UTP_TRANSFER_REQ_LIST_BASE_H);
>> > - ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
>> > - REG_UTP_TASK_REQ_LIST_BASE_L);
>> > - ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
>> > - REG_UTP_TASK_REQ_LIST_BASE_H);
>> > + /* enable UIC related interrupts */
>> > + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>> > +
>> > + ret = ufshcd_dme_link_startup(hba);
>> > + if (ret)
>> > + goto out;
>> >
>> > - /* Initialize unipro link startup procedure */
>> > - return ufshcd_dme_link_startup(hba);
>> > + ret = ufshcd_make_hba_operational(hba);
>> > + if (ret)
>> > + goto out;
>> > +
>> > +out:
>> > + dev_err(hba->dev, "link startup failed %d\n", ret);
>> > + return ret;
>> > }
>> >
>> > /**
>> > @@ -1176,12 +1259,19 @@ static int ufshcd_do_reset(struct ufs_hba
>> *hba)
>> > hba->outstanding_reqs = 0;
>> > hba->outstanding_tasks = 0;
>> >
>> > - /* start the initialization process */
>> > - if (ufshcd_initialize_hba(hba)) {
>> > + /* Host controller enable */
>> > + if (ufshcd_hba_enable(hba)) {
>> > dev_err(hba->dev,
>> > "Reset: Controller initialization failed\n");
>> > return FAILED;
>> > }
>> > +
>> > + if (ufshcd_link_startup(hba)) {
>> > + dev_err(hba->dev,
>> > + "Reset: Link start-up failed\n");
>> > + return FAILED;
>> > + }
>> > +
>> > return SUCCESS;
>> > }
>> >
>> > @@ -1434,6 +1524,17 @@ 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
>> > + */
>> > +static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
>> > +{
>> > + hba->active_uic_cmd->argument2 |=
>> > + ufshcd_get_uic_cmd_result(hba);
>> > + complete(&hba->active_uic_cmd->done);
>> > +}
>> > +
>> > +/**
>> > * ufshcd_transfer_req_compl - handle SCSI and query command
>> completion
>> > * @hba: per adapter instance
>> > */
>> > @@ -1473,28 +1574,6 @@ static void ufshcd_transfer_req_compl(struct
>> ufs_hba *hba)
>> > }
>> >
>> > /**
>> > - * ufshcd_uic_cc_handler - handle UIC command completion
>> > - * @work: pointer to a work queue structure
>> > - *
>> > - * Returns 0 on success, non-zero value on failure
>> > - */
>> > -static void ufshcd_uic_cc_handler (struct work_struct *work)
>> > -{
>> > - struct ufs_hba *hba;
>> > -
>> > - hba = container_of(work, struct ufs_hba, uic_workq);
>> > -
>> > - if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
>> > - !(ufshcd_get_uic_cmd_result(hba))) {
>> > -
>> > - if (ufshcd_make_hba_operational(hba))
>> > - dev_err(hba->dev,
>> > - "cc: hba not operational state\n");
>> > - return;
>> > - }
>> > -}
>> > -
>> > -/**
>> > * ufshcd_fatal_err_handler - handle fatal errors
>> > * @hba: per adapter instance
>> > */
>> > @@ -1555,7 +1634,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba,
>> u32 intr_status)
>> > ufshcd_err_handler(hba);
>> >
>> > if (intr_status & UIC_COMMAND_COMPL)
>> > - schedule_work(&hba->uic_workq);
>> > + ufshcd_uic_cmd_compl(hba);
>> >
>> > if (intr_status & UTP_TASK_REQ_COMPL)
>> > ufshcd_tmc_handler(hba);
>> > @@ -1778,6 +1857,21 @@ out:
>> > return err;
>> > }
>> >
>> > +/**
>> > + * ufshcd_async_scan - asynchronous execution for link startup
>> > + * @data: data pointer to pass to this function
>> > + * @cookie: cookie data
>> > + */
>> > +static void ufshcd_async_scan(void *data, async_cookie_t cookie)
>> > +{
>> > + struct ufs_hba *hba = (struct ufs_hba *)data;
>> > + int ret;
>> > +
>> > + ret = ufshcd_link_startup(hba);
>> > + if (!ret)
>> > + scsi_scan_host(hba->host);
>> > +}
>> > +
>> > static struct scsi_host_template ufshcd_driver_template = {
>> > .module = THIS_MODULE,
>> > .name = UFSHCD,
>> > @@ -1939,12 +2033,14 @@ int ufshcd_init(struct device *dev, struct
>> ufs_hba **hba_handle,
>> > init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
>> >
>> > /* Initialize work queues */
>> > - INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
>> > INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
>> >
>> > /* Initialize mutex for query requests */
>> > mutex_init(&hba->query.lock_ufs_query);
>> >
>> > + /* Initialize UIC command mutex */
>> > + mutex_init(&hba->uic_cmd_mutex);
>> > +
>> > /* IRQ registration */
>> > err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
>> > if (err) {
>> > @@ -1965,14 +2061,17 @@ int ufshcd_init(struct device *dev, struct
>> ufs_hba **hba_handle,
>> > goto out_free_irq;
>> > }
>> >
>> > - /* Initialization routine */
>> > - err = ufshcd_initialize_hba(hba);
>> > + /* Host controller enable */
>> > + err = ufshcd_hba_enable(hba);
>> > if (err) {
>> > - dev_err(hba->dev, "Initialization failed\n");
>> > + dev_err(hba->dev, "Host controller enable failed\n");
>> > goto out_remove_scsi_host;
>> > }
>> > +
>> > *hba_handle = hba;
>> >
>> > + async_schedule(ufshcd_async_scan, hba);
>> > +
>> > return 0;
>> >
>> > out_remove_scsi_host:
>> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
>> > index d98e046..974bd07 100644
>> > --- a/drivers/scsi/ufs/ufshcd.h
>> > +++ b/drivers/scsi/ufs/ufshcd.h
>> > @@ -51,6 +51,7 @@
>> > #include <linux/bitops.h>
>> > #include <linux/pm_runtime.h>
>> > #include <linux/clk.h>
>> > +#include <linux/completion.h>
>> >
>> > #include <asm/irq.h>
>> > #include <asm/byteorder.h>
>> > @@ -76,6 +77,7 @@
>> > * @argument3: UIC command argument 3
>> > * @cmd_active: Indicate if UIC command is outstanding
>> > * @result: UIC command result
>> > + * @done: UIC command completion
>> > */
>> > struct uic_command {
>> > u32 command;
>> > @@ -84,6 +86,7 @@ struct uic_command {
>> > u32 argument3;
>> > int cmd_active;
>> > int result;
>> > + struct completion done;
>> > };
>> >
>> > /**
>> > @@ -150,11 +153,11 @@ struct ufs_query {
>> > * @ufs_version: UFS Version to which controller complies
>> > * @irq: Irq number of the controller
>> > * @active_uic_cmd: handle of active UIC command
>> > + * @uic_cmd_mutex: mutex for uic command
>> > * @ufshcd_tm_wait_queue: wait queue for task management
>> > * @tm_condition: condition variable for task management
>> > * @ufshcd_state: UFSHCD states
>> > * @intr_mask: Interrupt Mask Bits
>> > - * @uic_workq: Work queue for UIC completion handling
>> > * @feh_workq: Work queue for fatal controller error handling
>> > * @errors: HBA errors
>> > * @query: query request information
>> > @@ -186,7 +189,9 @@ struct ufs_hba {
>> > u32 ufs_version;
>> > unsigned int irq;
>> >
>> > - struct uic_command active_uic_cmd;
>> > + struct uic_command *active_uic_cmd;
>> > + struct mutex uic_cmd_mutex;
>> > +
>> > wait_queue_head_t ufshcd_tm_wait_queue;
>> > unsigned long tm_condition;
>> >
>> > @@ -194,7 +199,6 @@ struct ufs_hba {
>> > u32 intr_mask;
>> >
>> > /* Work Queues */
>> > - struct work_struct uic_workq;
>> > struct work_struct feh_workq;
>> >
>> > /* HBA Errors */
>> >
>>
>> --
>> Regards,
>> Sujit
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations
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
1 sibling, 1 reply; 52+ messages in thread
From: Santosh Y @ 2013-05-06 19:30 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Mon, May 6, 2013 at 11:07 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Simplify operations with hiding mmio_base.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 105 +++++++++++++++++++--------------------------
> drivers/scsi/ufs/ufshcd.h | 7 +++-
> 2 files changed, 50 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index f244812..cf7c8e4 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -71,7 +71,7 @@ enum {
> */
> static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UFS_VERSION);
> + return ufshcd_readl(hba, REG_UFS_VERSION);
> }
>
> /**
> @@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
> */
> static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
> {
> - writel(~(1 << pos),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
> + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> }
>
> /**
> @@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
> */
> static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
> + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
> MASK_UIC_COMMAND_RESULT;
> }
>
> @@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
> {
> switch (option) {
> case INT_AGGR_RESET:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_COUNTER_AND_TIMER_RESET),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE |
> + INT_AGGR_COUNTER_AND_TIMER_RESET,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> case INT_AGGR_CONFIG:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_PARAM_WRITE |
> - INT_AGGR_COUNTER_THRESHOLD_VALUE |
> - INT_AGGR_TIMEOUT_VALUE),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
> + INT_AGGR_COUNTER_THRESHOLD_VALUE |
> + INT_AGGR_TIMEOUT_VALUE,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> }
> }
> @@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
> */
> static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> {
> - writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TASK_REQ_LIST_RUN_STOP));
> - writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
> + ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TASK_REQ_LIST_RUN_STOP);
> + ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
> }
>
> /**
> @@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> */
> static inline void ufshcd_hba_start(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
> }
>
> /**
> @@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> */
> static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
> {
> - return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> }
>
> /**
> @@ -299,8 +293,7 @@ static inline
> void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
> {
> __set_bit(task_tag, &hba->outstanding_reqs);
> - writel((1 << task_tag),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> }
>
> /**
> @@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
> */
> static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> {
> - hba->capabilities =
> - readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
> + hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
>
> /* nutrs and nutmrs are 0 based values */
> hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
> @@ -399,16 +391,13 @@ static inline void
> ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> {
> /* Write Args */
> - writel(uic_cmnd->argument1,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
> - writel(uic_cmnd->argument2,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
> - writel(uic_cmnd->argument3,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
> + ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> + ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> + ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
>
> /* Write UIC Cmd */
> - writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
> - (hba->mmio_base + REG_UIC_COMMAND));
> + ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> + REG_UIC_COMMAND);
> }
>
> /**
> @@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
> {
> switch (option) {
> case UFSHCD_INT_ENABLE:
> - writel(hba->int_enable_mask,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> break;
> case UFSHCD_INT_DISABLE:
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(INTERRUPT_DISABLE_MASK_10,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> + REG_INTERRUPT_ENABLE);
> else
> - writel(INTERRUPT_DISABLE_MASK_11,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> + REG_INTERRUPT_ENABLE);
> break;
> }
> }
> @@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> unsigned long flags;
>
> /* check if controller is ready to accept UIC commands */
> - if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
> + if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> UIC_COMMAND_READY) == 0x0) {
> dev_err(hba->dev,
> "Controller not ready"
> @@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> u32 reg;
>
> /* check if device present */
> - reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
> + reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
> if (!ufshcd_is_device_present(reg)) {
> dev_err(hba->dev, "cc: Device not present\n");
> err = -ENXIO;
> @@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
> return -EIO;
>
> /* Configure UTRL and UTMRL base address registers */
> - writel(lower_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
> - writel(lower_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_H);
>
> /* Initialize unipro link startup procedure */
> return ufshcd_dme_link_startup(hba);
> @@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
> int index;
>
> lrb = hba->lrb;
> - tr_doorbell =
> - readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
> + tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
>
> for (index = 0; index < hba->nutrs; index++) {
> @@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
> goto fatal_eh;
>
> if (hba->errors & UIC_ERROR) {
> -
> - reg = readl(hba->mmio_base +
> - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> goto fatal_eh;
> }
> @@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
> {
> u32 tm_doorbell;
>
> - tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
> + tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
> hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
> wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
> }
> @@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
> struct ufs_hba *hba = __hba;
>
> spin_lock(hba->host->host_lock);
> - intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
> + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
>
> if (intr_status) {
> ufshcd_sl_intr(hba, intr_status);
>
> /* If UFSHCI 1.0 then clear interrupt status register */
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(intr_status,
> - (hba->mmio_base + REG_INTERRUPT_STATUS));
> + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> retval = IRQ_HANDLED;
> }
> spin_unlock(hba->host->host_lock);
> @@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>
> /* send command to the controller */
> __set_bit(free_slot, &hba->outstanding_tasks);
> - writel((1 << free_slot),
> - (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
>
> spin_unlock_irqrestore(host->host_lock, flags);
>
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 336980b..6429bed 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -204,6 +204,11 @@ struct ufs_hba {
> struct ufs_query query;
> };
>
> +#define ufshcd_writel(hba, val, reg) \
> + writel((val), (hba)->mmio_base + (reg))
> +#define ufshcd_readl(hba, reg) \
> + readl((hba)->mmio_base + (reg))
> +
> int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
> @@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
> */
> static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> }
>
> #endif /* End of Header */
> --
> 1.7.0.4
>
Still git throws the same error "fatal: cannot convert from
ks_c_5601-1987 to UTF-8". Please check it for all the patches.
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3 5/6] scsi: ufs: add dme configuration primitives
2013-05-06 5:37 ` [PATCH v3 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
@ 2013-05-06 19:43 ` Santosh Y
0 siblings, 0 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-06 19:43 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
>
> /**
> + * ufshcd_dme_xxx_set - UIC command for DME_SET, DME_PEER_SET
> + * @hba: per adapter instance
> + * @attr_sel: uic command argument1
> + * @attr_set: attribute set type as uic command argument2
> + * @mib_val: setting value as uic command argument3
> + * @peer: indicate wherter peer or non-peer
> + *
> + * Returns 0 on success, non-zero value on failure
> + */
> +int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val, u8 peer)
> +{
> + struct uic_command uic_cmd = {0};
> + static const char *const action[] = {
> + "dme-set",
> + "dme-peer-set"
> + };
> + const char *set = action[!!peer];
> + int ret;
> +
> + uic_cmd.command = peer ?
> + UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
> + uic_cmd.argument1 = attr_sel;
> + uic_cmd.argument2 = UIC_ARG_ATTR_SET(attr_set);
> + uic_cmd.argument3 = mib_val;
> +
> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> +
> + dev_dbg(hba->dev, "%s: error code %d\n", set, ret);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_set);
> +
> +/**
> + * ufshcd_dme_xxx_get - UIC command for DME_GET, DME_PEER_GET
> + * @hba: per adapter instance
> + * @attr_sel: uic command argument1
> + * @mib_val: the value of the attribute as returned by the UIC command
> + * @peer: indicate wherter peer or non-peer
> + *
> + * Returns 0 on success, non-zero value on failure
> + */
> +int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
> + u32 *mib_val, u8 peer)
> +{
> + struct uic_command uic_cmd = {0};
> + static const char *const action[] = {
> + "dme-get",
> + "dme-peer-get"
> + };
> + const char *get = action[!!peer];
> + int ret;
> +
> + uic_cmd.command = peer ?
> + UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
> + uic_cmd.argument1 = attr_sel;
> +
> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> +
> + if (mib_val)
> + *mib_val = uic_cmd.argument3;
> +
> + dev_dbg(hba->dev, "%s: error code %d\n", get, ret);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ufshcd_dme_xxx_get);
> +
> +/**
> * ufshcd_make_hba_operational - Make UFS controller operational
> * @hba: per adapter instance
> *
> @@ -1531,6 +1613,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
> {
> 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);
> }
>
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 974bd07..93965b9 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -217,6 +217,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
>
> +extern int ufshcd_dme_xxx_set(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val, u8 peer);
> +extern int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel,
> + u32 *mib_val, u8 peer);
> +
> /**
> * ufshcd_hba_stop - Send controller to reset state
> * @hba: per adapter instance
> @@ -226,4 +231,29 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> }
>
> +/* UIC command interfaces for DME primitives */
> +static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val)
> +{
> + return ufshcd_dme_xxx_set(hba, attr_sel, attr_set, mib_val, 0);
> +}
> +
> +static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val)
> +{
> + return ufshcd_dme_xxx_set(hba, attr_sel, attr_set, mib_val, 1);
> +}
> +
> +static inline int ufshcd_dme_get(struct ufs_hba *hba,
> + u32 attr_sel, u32 *mib_val)
> +{
> + return ufshcd_dme_xxx_get(hba, attr_sel, mib_val, 0);
> +}
> +
> +static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
> + u32 attr_sel, u32 *mib_val)
> +{
> + return ufshcd_dme_xxx_get(hba, attr_sel, mib_val, 1);
> +}
> +
ufshcd_dme_xxx_get/set() are being used to configure attributes. So it
is better to rename them as ufshcd_dme_attr_get/set().
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v3 6/6] scsi: ufs: add dme control primitives
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
0 siblings, 1 reply; 52+ messages in thread
From: Santosh Y @ 2013-05-06 19:51 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
> /**
> + * ufshcd_dme_power_xxx - 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_xxx(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_xxx);
> +
> +/**
> + * ufshcd_dme_hibern8_xxx - 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_xxx(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:%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_xxx);
> +
power/hibernate functions can also be renamed as
ufshcd_dme_power/hibernate_config(struct ufs_hba *hba, bool
enable/enter) or similar instead of xxx.
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v3 6/6] scsi: ufs: add dme control primitives
2013-05-06 19:51 ` Santosh Y
@ 2013-05-07 3:45 ` Seungwon Jeon
0 siblings, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-07 3:45 UTC (permalink / raw)
To: 'Santosh Y'
Cc: linux-scsi, 'Vinayak Holikatti',
'James E.J. Bottomley'
On Tuesday, May 07, 2013, Santosh Y wrote:
> > /**
> > + * ufshcd_dme_power_xxx - 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_xxx(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_xxx);
> > +
> > +/**
> > + * ufshcd_dme_hibern8_xxx - 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_xxx(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:%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_xxx);
> > +
>
>
> power/hibernate functions can also be renamed as
> ufshcd_dme_power/hibernate_config(struct ufs_hba *hba, bool
> enable/enter) or similar instead of xxx.
Ok, I'll change the names including dme_get/set.
If you have further views, please let me know.
Thanks,
Seungwon Jeon
>
>
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations
2013-05-06 19:30 ` Santosh Y
@ 2013-05-07 3:52 ` Seungwon Jeon
0 siblings, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-07 3:52 UTC (permalink / raw)
To: 'Santosh Y'
Cc: linux-scsi, 'Vinayak Holikatti',
'James E.J. Bottomley'
On Tuesday, May 07, 2013, Santosh Y wrote:
> On Mon, May 6, 2013 at 11:07 AM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Simplify operations with hiding mmio_base.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > Tested-by: Maya Erez <merez@codeaurora.org>
> > ---
> > drivers/scsi/ufs/ufshcd.c | 105 +++++++++++++++++++--------------------------
> > drivers/scsi/ufs/ufshcd.h | 7 +++-
> > 2 files changed, 50 insertions(+), 62 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> > index f244812..cf7c8e4 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -71,7 +71,7 @@ enum {
> > */
> > static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
> > {
> > - return readl(hba->mmio_base + REG_UFS_VERSION);
> > + return ufshcd_readl(hba, REG_UFS_VERSION);
> > }
> >
> > /**
> > @@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
> > */
> > static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
> > {
> > - writel(~(1 << pos),
> > - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
> > + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> > }
> >
> > /**
> > @@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
> > */
> > static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> > {
> > - return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
> > + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
> > MASK_UIC_COMMAND_RESULT;
> > }
> >
> > @@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
> > {
> > switch (option) {
> > case INT_AGGR_RESET:
> > - writel((INT_AGGR_ENABLE |
> > - INT_AGGR_COUNTER_AND_TIMER_RESET),
> > - (hba->mmio_base +
> > - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> > + ufshcd_writel(hba, INT_AGGR_ENABLE |
> > + INT_AGGR_COUNTER_AND_TIMER_RESET,
> > + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> > break;
> > case INT_AGGR_CONFIG:
> > - writel((INT_AGGR_ENABLE |
> > - INT_AGGR_PARAM_WRITE |
> > - INT_AGGR_COUNTER_THRESHOLD_VALUE |
> > - INT_AGGR_TIMEOUT_VALUE),
> > - (hba->mmio_base +
> > - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> > + ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
> > + INT_AGGR_COUNTER_THRESHOLD_VALUE |
> > + INT_AGGR_TIMEOUT_VALUE,
> > + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> > break;
> > }
> > }
> > @@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
> > */
> > static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> > {
> > - writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> > - (hba->mmio_base +
> > - REG_UTP_TASK_REQ_LIST_RUN_STOP));
> > - writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> > - (hba->mmio_base +
> > - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
> > + ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> > + REG_UTP_TASK_REQ_LIST_RUN_STOP);
> > + ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> > + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
> > }
> >
> > /**
> > @@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> > */
> > static inline void ufshcd_hba_start(struct ufs_hba *hba)
> > {
> > - writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > + ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
> > }
> >
> > /**
> > @@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> > */
> > static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
> > {
> > - return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> > + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> > }
> >
> > /**
> > @@ -299,8 +293,7 @@ static inline
> > void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
> > {
> > __set_bit(task_tag, &hba->outstanding_reqs);
> > - writel((1 << task_tag),
> > - (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
> > + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> > }
> >
> > /**
> > @@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
> > */
> > static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> > {
> > - hba->capabilities =
> > - readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
> > + hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
> >
> > /* nutrs and nutmrs are 0 based values */
> > hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
> > @@ -399,16 +391,13 @@ static inline void
> > ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> > {
> > /* Write Args */
> > - writel(uic_cmnd->argument1,
> > - (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
> > - writel(uic_cmnd->argument2,
> > - (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
> > - writel(uic_cmnd->argument3,
> > - (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
> > + ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> > + ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> > + ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
> >
> > /* Write UIC Cmd */
> > - writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
> > - (hba->mmio_base + REG_UIC_COMMAND));
> > + ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> > + REG_UIC_COMMAND);
> > }
> >
> > /**
> > @@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
> > {
> > switch (option) {
> > case UFSHCD_INT_ENABLE:
> > - writel(hba->int_enable_mask,
> > - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> > + ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> > break;
> > case UFSHCD_INT_DISABLE:
> > if (hba->ufs_version == UFSHCI_VERSION_10)
> > - writel(INTERRUPT_DISABLE_MASK_10,
> > - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> > + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> > + REG_INTERRUPT_ENABLE);
> > else
> > - writel(INTERRUPT_DISABLE_MASK_11,
> > - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> > + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> > + REG_INTERRUPT_ENABLE);
> > break;
> > }
> > }
> > @@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> > unsigned long flags;
> >
> > /* check if controller is ready to accept UIC commands */
> > - if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
> > + if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> > UIC_COMMAND_READY) == 0x0) {
> > dev_err(hba->dev,
> > "Controller not ready"
> > @@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> > u32 reg;
> >
> > /* check if device present */
> > - reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
> > + reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
> > if (!ufshcd_is_device_present(reg)) {
> > dev_err(hba->dev, "cc: Device not present\n");
> > err = -ENXIO;
> > @@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
> > return -EIO;
> >
> > /* Configure UTRL and UTMRL base address registers */
> > - writel(lower_32_bits(hba->utrdl_dma_addr),
> > - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
> > - writel(upper_32_bits(hba->utrdl_dma_addr),
> > - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
> > - writel(lower_32_bits(hba->utmrdl_dma_addr),
> > - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
> > - writel(upper_32_bits(hba->utmrdl_dma_addr),
> > - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
> > + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> > + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> > + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> > + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> > + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> > + REG_UTP_TASK_REQ_LIST_BASE_L);
> > + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> > + REG_UTP_TASK_REQ_LIST_BASE_H);
> >
> > /* Initialize unipro link startup procedure */
> > return ufshcd_dme_link_startup(hba);
> > @@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
> > int index;
> >
> > lrb = hba->lrb;
> > - tr_doorbell =
> > - readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
> > + tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> > completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
> >
> > for (index = 0; index < hba->nutrs; index++) {
> > @@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
> > goto fatal_eh;
> >
> > if (hba->errors & UIC_ERROR) {
> > -
> > - reg = readl(hba->mmio_base +
> > - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> > + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> > if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> > goto fatal_eh;
> > }
> > @@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
> > {
> > u32 tm_doorbell;
> >
> > - tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
> > + tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
> > hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
> > wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
> > }
> > @@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
> > struct ufs_hba *hba = __hba;
> >
> > spin_lock(hba->host->host_lock);
> > - intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
> > + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
> >
> > if (intr_status) {
> > ufshcd_sl_intr(hba, intr_status);
> >
> > /* If UFSHCI 1.0 then clear interrupt status register */
> > if (hba->ufs_version == UFSHCI_VERSION_10)
> > - writel(intr_status,
> > - (hba->mmio_base + REG_INTERRUPT_STATUS));
> > + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> > retval = IRQ_HANDLED;
> > }
> > spin_unlock(hba->host->host_lock);
> > @@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
> >
> > /* send command to the controller */
> > __set_bit(free_slot, &hba->outstanding_tasks);
> > - writel((1 << free_slot),
> > - (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
> > + ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
> >
> > spin_unlock_irqrestore(host->host_lock, flags);
> >
> > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> > index 336980b..6429bed 100644
> > --- a/drivers/scsi/ufs/ufshcd.h
> > +++ b/drivers/scsi/ufs/ufshcd.h
> > @@ -204,6 +204,11 @@ struct ufs_hba {
> > struct ufs_query query;
> > };
> >
> > +#define ufshcd_writel(hba, val, reg) \
> > + writel((val), (hba)->mmio_base + (reg))
> > +#define ufshcd_readl(hba, reg) \
> > + readl((hba)->mmio_base + (reg))
> > +
> > int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> > unsigned int);
> > void ufshcd_remove(struct ufs_hba *);
> > @@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
> > */
> > static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> > {
> > - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> > + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> > }
> >
> > #endif /* End of Header */
> > --
> > 1.7.0.4
> >
>
> Still git throws the same error "fatal: cannot convert from
> ks_c_5601-1987 to UTF-8". Please check it for all the patches.
Um...
Ok. Let me send test one for you, first.
Thanks,
Seungwon Jeon
>
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (6 preceding siblings ...)
2013-05-06 5:39 ` [PATCH v3 6/6] scsi: ufs: add dme control primitives Seungwon Jeon
@ 2013-05-08 8:41 ` Seungwon Jeon
2013-05-08 11:58 ` merez
2013-05-08 15:18 ` Santosh Y
2013-05-08 8:41 ` [PATCH v4 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
` (5 subsequent siblings)
13 siblings, 2 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-08 8:41 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Simplify operations with hiding mmio_base.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 105 +++++++++++++++++++--------------------------
drivers/scsi/ufs/ufshcd.h | 7 +++-
2 files changed, 50 insertions(+), 62 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f244812..cf7c8e4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -71,7 +71,7 @@ enum {
*/
static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
{
- return readl(hba->mmio_base + REG_UFS_VERSION);
+ return ufshcd_readl(hba, REG_UFS_VERSION);
}
/**
@@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
*/
static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
{
- writel(~(1 << pos),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
+ ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
}
/**
@@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
*/
static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
{
- return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
MASK_UIC_COMMAND_RESULT;
}
@@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
{
switch (option) {
case INT_AGGR_RESET:
- writel((INT_AGGR_ENABLE |
- INT_AGGR_COUNTER_AND_TIMER_RESET),
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ ufshcd_writel(hba, INT_AGGR_ENABLE |
+ INT_AGGR_COUNTER_AND_TIMER_RESET,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
case INT_AGGR_CONFIG:
- writel((INT_AGGR_ENABLE |
- INT_AGGR_PARAM_WRITE |
- INT_AGGR_COUNTER_THRESHOLD_VALUE |
- INT_AGGR_TIMEOUT_VALUE),
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
+ ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+ INT_AGGR_COUNTER_THRESHOLD_VALUE |
+ INT_AGGR_TIMEOUT_VALUE,
+ REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
break;
}
}
@@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
*/
static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
{
- writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
- (hba->mmio_base +
- REG_UTP_TASK_REQ_LIST_RUN_STOP));
- writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
- (hba->mmio_base +
- REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
+ ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TASK_REQ_LIST_RUN_STOP);
+ ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
+ REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
}
/**
@@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
*/
static inline void ufshcd_hba_start(struct ufs_hba *hba)
{
- writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
+ ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
}
/**
@@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
*/
static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
{
- return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
+ return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
}
/**
@@ -299,8 +293,7 @@ static inline
void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
{
__set_bit(task_tag, &hba->outstanding_reqs);
- writel((1 << task_tag),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
+ ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
}
/**
@@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
*/
static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
{
- hba->capabilities =
- readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
+ hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
/* nutrs and nutmrs are 0 based values */
hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
@@ -399,16 +391,13 @@ static inline void
ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
{
/* Write Args */
- writel(uic_cmnd->argument1,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
- writel(uic_cmnd->argument2,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
- writel(uic_cmnd->argument3,
- (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
+ ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
/* Write UIC Cmd */
- writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
- (hba->mmio_base + REG_UIC_COMMAND));
+ ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+ REG_UIC_COMMAND);
}
/**
@@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
{
switch (option) {
case UFSHCD_INT_ENABLE:
- writel(hba->int_enable_mask,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
break;
case UFSHCD_INT_DISABLE:
if (hba->ufs_version == UFSHCI_VERSION_10)
- writel(INTERRUPT_DISABLE_MASK_10,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
+ REG_INTERRUPT_ENABLE);
else
- writel(INTERRUPT_DISABLE_MASK_11,
- (hba->mmio_base + REG_INTERRUPT_ENABLE));
+ ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
+ REG_INTERRUPT_ENABLE);
break;
}
}
@@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
unsigned long flags;
/* check if controller is ready to accept UIC commands */
- if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
+ if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
UIC_COMMAND_READY) == 0x0) {
dev_err(hba->dev,
"Controller not ready"
@@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
u32 reg;
/* check if device present */
- reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
+ reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
if (!ufshcd_is_device_present(reg)) {
dev_err(hba->dev, "cc: Device not present\n");
err = -ENXIO;
@@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
return -EIO;
/* Configure UTRL and UTMRL base address registers */
- writel(lower_32_bits(hba->utrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
- writel(upper_32_bits(hba->utrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
- writel(lower_32_bits(hba->utmrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
- writel(upper_32_bits(hba->utmrdl_dma_addr),
- (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
+ ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
/* Initialize unipro link startup procedure */
return ufshcd_dme_link_startup(hba);
@@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
int index;
lrb = hba->lrb;
- tr_doorbell =
- readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
+ tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
for (index = 0; index < hba->nutrs; index++) {
@@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
goto fatal_eh;
if (hba->errors & UIC_ERROR) {
-
- reg = readl(hba->mmio_base +
- REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
+ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
goto fatal_eh;
}
@@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
{
u32 tm_doorbell;
- tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
+ tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
}
@@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
struct ufs_hba *hba = __hba;
spin_lock(hba->host->host_lock);
- intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
if (intr_status) {
ufshcd_sl_intr(hba, intr_status);
/* If UFSHCI 1.0 then clear interrupt status register */
if (hba->ufs_version == UFSHCI_VERSION_10)
- writel(intr_status,
- (hba->mmio_base + REG_INTERRUPT_STATUS));
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
@@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
/* send command to the controller */
__set_bit(free_slot, &hba->outstanding_tasks);
- writel((1 << free_slot),
- (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
+ ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
spin_unlock_irqrestore(host->host_lock, flags);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 336980b..6429bed 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -204,6 +204,11 @@ struct ufs_hba {
struct ufs_query query;
};
+#define ufshcd_writel(hba, val, reg) \
+ writel((val), (hba)->mmio_base + (reg))
+#define ufshcd_readl(hba, reg) \
+ readl((hba)->mmio_base + (reg))
+
int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
@@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
*/
static inline void ufshcd_hba_stop(struct ufs_hba *hba)
{
- writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
+ ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
}
#endif /* End of Header */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v4 2/6] scsi: ufs: amend interrupt configuration
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (7 preceding siblings ...)
2013-05-08 8:41 ` [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations Seungwon Jeon
@ 2013-05-08 8:41 ` 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
` (4 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-08 8:41 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
It makes interrupt setting more flexible especially
for disabling. And wrong bit mask is fixed for ver 1.0.
[17:16] is added for mask.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 84 +++++++++++++++++++++++++++++++-------------
drivers/scsi/ufs/ufshcd.h | 4 +-
drivers/scsi/ufs/ufshci.h | 5 ++-
3 files changed, 64 insertions(+), 29 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index cf7c8e4..feaf221 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -35,6 +35,10 @@
#include "ufshcd.h"
+#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
+ UTP_TASK_REQ_COMPL |\
+ UFSHCD_ERROR_MASK)
+
enum {
UFSHCD_MAX_CHANNEL = 0,
UFSHCD_MAX_ID = 1,
@@ -64,6 +68,20 @@ enum {
};
/**
+ * ufshcd_get_intr_mask - Get the interrupt bit mask
+ * @hba - Pointer to adapter instance
+ *
+ * Returns interrupt bit mask per version
+ */
+static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
+{
+ if (hba->ufs_version == UFSHCI_VERSION_10)
+ return INTERRUPT_MASK_ALL_VER_10;
+ else
+ return INTERRUPT_MASK_ALL_VER_11;
+}
+
+/**
* ufshcd_get_ufs_version - Get the UFS version supported by the HBA
* @hba - Pointer to adapter instance
*
@@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
}
/**
- * ufshcd_int_config - enable/disable interrupts
+ * ufshcd_enable_intr - enable interrupts
* @hba: per adapter instance
- * @option: interrupt option
+ * @intrs: interrupt bits
*/
-static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
+static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
{
- switch (option) {
- case UFSHCD_INT_ENABLE:
- ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
- break;
- case UFSHCD_INT_DISABLE:
- if (hba->ufs_version == UFSHCI_VERSION_10)
- ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
- REG_INTERRUPT_ENABLE);
- else
- ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
- REG_INTERRUPT_ENABLE);
- break;
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+ if (hba->ufs_version == UFSHCI_VERSION_10) {
+ u32 rw;
+ rw = set & INTERRUPT_MASK_RW_VER_10;
+ set = rw | ((set ^ intrs) & intrs);
+ } else {
+ set |= intrs;
+ }
+
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
+}
+
+/**
+ * ufshcd_disable_intr - disable interrupts
+ * @hba: per adapter instance
+ * @intrs: interrupt bits
+ */
+static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
+{
+ u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+
+ if (hba->ufs_version == UFSHCI_VERSION_10) {
+ u32 rw;
+ rw = (set & INTERRUPT_MASK_RW_VER_10) &
+ ~(intrs & INTERRUPT_MASK_RW_VER_10);
+ set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
+
+ } else {
+ set &= ~intrs;
}
+
+ ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
}
/**
@@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
uic_cmd->argument3 = 0;
/* enable UIC related interrupts */
- hba->int_enable_mask |= UIC_COMMAND_COMPL;
- ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
/* sending UIC commands to controller */
ufshcd_send_uic_command(hba, uic_cmd);
@@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
}
/* Enable required interrupts */
- hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
- UIC_ERROR |
- UTP_TASK_REQ_COMPL |
- DEVICE_FATAL_ERROR |
- CONTROLLER_FATAL_ERROR |
- SYSTEM_BUS_FATAL_ERROR);
- ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
/* Configure interrupt aggregation */
ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
@@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
void ufshcd_remove(struct ufs_hba *hba)
{
/* disable interrupts */
- ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
+ ufshcd_disable_intr(hba, hba->intr_mask);
ufshcd_hba_stop(hba);
ufshcd_hba_free(hba);
@@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
/* Get UFS version supported by the controller */
hba->ufs_version = ufshcd_get_ufs_version(hba);
+ /* Get Interrupt bit mask per version */
+ hba->intr_mask = ufshcd_get_intr_mask(hba);
+
/* Allocate memory for host memory space */
err = ufshcd_memory_alloc(hba);
if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 6429bed..d98e046 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -153,7 +153,7 @@ struct ufs_query {
* @ufshcd_tm_wait_queue: wait queue for task management
* @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
- * @int_enable_mask: Interrupt Mask Bits
+ * @intr_mask: Interrupt Mask Bits
* @uic_workq: Work queue for UIC completion handling
* @feh_workq: Work queue for fatal controller error handling
* @errors: HBA errors
@@ -191,7 +191,7 @@ struct ufs_hba {
unsigned long tm_condition;
u32 ufshcd_state;
- u32 int_enable_mask;
+ u32 intr_mask;
/* Work Queues */
struct work_struct uic_workq;
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index 4a86247..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -232,10 +232,11 @@ enum {
/* Interrupt disable masks */
enum {
/* Interrupt disable mask for UFSHCI v1.0 */
- INTERRUPT_DISABLE_MASK_10 = 0xFFFF,
+ INTERRUPT_MASK_ALL_VER_10 = 0x30FFF,
+ INTERRUPT_MASK_RW_VER_10 = 0x30000,
/* Interrupt disable mask for UFSHCI v1.1 */
- INTERRUPT_DISABLE_MASK_11 = 0x0,
+ INTERRUPT_MASK_ALL_VER_11 = 0x31FFF,
};
/*
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v4 3/6] scsi: ufs: fix interrupt status clears
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (8 preceding siblings ...)
2013-05-08 8:41 ` [PATCH v4 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
@ 2013-05-08 8:41 ` 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
` (3 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-08 8:41 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
drivers/scsi/ufs/ufshcd.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index feaf221..e04c74e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1582,11 +1582,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
if (intr_status) {
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
ufshcd_sl_intr(hba, intr_status);
-
- /* If UFSHCI 1.0 then clear interrupt status register */
- if (hba->ufs_version == UFSHCI_VERSION_10)
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
retval = IRQ_HANDLED;
}
spin_unlock(hba->host->host_lock);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v4 4/6] scsi: ufs: rework link start-up process
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (9 preceding siblings ...)
2013-05-08 8:41 ` [PATCH v4 3/6] scsi: ufs: fix interrupt status clears Seungwon Jeon
@ 2013-05-08 8:42 ` 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
` (2 subsequent siblings)
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-08 8:42 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Link start-up requires long time with multiphase handshakes
between UFS host and device. This affects driver's probe time.
This patch let link start-up run asynchronously. Link start-up
will be executed at the end of prove separately.
Along with this change, the following is worked.
Defined completion time of uic command to avoid a permanent wait.
Added mutex to guarantee of uic command at a time.
Adapted some sequence of controller initialization after link statup
according to HCI standard.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
Tested-by: Maya Erez <merez@codeaurora.org>
---
Change in v4:
- Addressed late interrupt case (Sujit).
- Move print message in link startup (Maya).
drivers/scsi/ufs/ufshcd.c | 295 ++++++++++++++++++++++++++++++--------------
drivers/scsi/ufs/ufshcd.h | 10 +-
2 files changed, 208 insertions(+), 97 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e04c74e..8363b92 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -33,11 +33,15 @@
* this program.
*/
+#include <linux/async.h>
+
#include "ufshcd.h"
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
UTP_TASK_REQ_COMPL |\
UFSHCD_ERROR_MASK)
+/* UIC command timeout, unit: ms */
+#define UIC_CMD_TIMEOUT 500
enum {
UFSHCD_MAX_CHANNEL = 0,
@@ -401,24 +405,122 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
}
/**
- * ufshcd_send_uic_command - Send UIC commands to unipro layers
+ * ufshcd_ready_for_uic_cmd - Check if controller is ready
+ * to accept UIC commands
* @hba: per adapter instance
- * @uic_command: UIC command
+ * Return true on success, else false
+ */
+static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
+{
+ if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Mutex must be held.
*/
static inline void
-ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
{
+ WARN_ON(hba->active_uic_cmd);
+
+ hba->active_uic_cmd = uic_cmd;
+
/* Write Args */
- ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
- ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
- ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
+ ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
+ ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
+ ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
/* Write UIC Cmd */
- ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
+ ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
REG_UIC_COMMAND);
}
/**
+ * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
+ * @hba: per adapter instance
+ * @uic_command: UIC command
+ *
+ * Must be called with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+ unsigned long flags;
+
+ if (wait_for_completion_timeout(&uic_cmd->done,
+ msecs_to_jiffies(UIC_CMD_TIMEOUT)))
+ ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
+ else
+ ret = -ETIMEDOUT;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->active_uic_cmd = NULL;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return ret;
+}
+
+/**
+ * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
+ * with mutex held.
+ * Returns 0 only if success.
+ */
+static int
+__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+ unsigned long flags;
+
+ if (!ufshcd_ready_for_uic_cmd(hba)) {
+ dev_err(hba->dev,
+ "Controller not ready to accept UIC commands\n");
+ return -EIO;
+ }
+
+ init_completion(&uic_cmd->done);
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ ufshcd_dispatch_uic_cmd(hba, uic_cmd);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
+
+ return ret;
+}
+
+/**
+ * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
+ * @hba: per adapter instance
+ * @uic_cmd: UIC command
+ *
+ * Returns 0 only if success.
+ */
+static int
+ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
+{
+ int ret;
+
+ mutex_lock(&hba->uic_cmd_mutex);
+ ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
+ mutex_unlock(&hba->uic_cmd_mutex);
+
+ return ret;
+}
+
+/**
* ufshcd_map_sg - Map scatter-gather list to prdt
* @lrbp - pointer to local reference block
*
@@ -962,34 +1064,16 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
*/
static int ufshcd_dme_link_startup(struct ufs_hba *hba)
{
- struct uic_command *uic_cmd;
- unsigned long flags;
-
- /* check if controller is ready to accept UIC commands */
- if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
- UIC_COMMAND_READY) == 0x0) {
- dev_err(hba->dev,
- "Controller not ready"
- " to accept UIC commands\n");
- return -EIO;
- }
+ struct uic_command uic_cmd = {0};
+ int ret;
- spin_lock_irqsave(hba->host->host_lock, flags);
+ uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
- /* form UIC command */
- uic_cmd = &hba->active_uic_cmd;
- uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
- uic_cmd->argument1 = 0;
- uic_cmd->argument2 = 0;
- uic_cmd->argument3 = 0;
-
- /* enable UIC related interrupts */
- ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
-
- /* sending UIC commands to controller */
- ufshcd_send_uic_command(hba, uic_cmd);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- return 0;
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_err(hba->dev,
+ "dme-link-startup: error code %d\n", ret);
+ return ret;
}
/**
@@ -998,9 +1082,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
*
* To bring UFS host controller to operational state,
* 1. Check if device is present
- * 2. Configure run-stop-registers
- * 3. Enable required interrupts
- * 4. Configure interrupt aggregation
+ * 2. Enable required interrupts
+ * 3. Configure interrupt aggregation
+ * 4. Program UTRL and UTMRL base addres
+ * 5. Configure run-stop-registers
*
* Returns 0 on success, non-zero value on failure
*/
@@ -1017,6 +1102,22 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
goto out;
}
+ /* Enable required interrupts */
+ ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
+
+ /* Configure interrupt aggregation */
+ ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+
+ /* Configure UTRL and UTMRL base address registers */
+ ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
+ REG_UTP_TRANSFER_REQ_LIST_BASE_H);
+ ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_L);
+ ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
+ REG_UTP_TASK_REQ_LIST_BASE_H);
+
/*
* UCRDY, UTMRLDY and UTRLRDY bits must be 1
* DEI, HEI bits must be 0
@@ -1030,17 +1131,11 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
goto out;
}
- /* Enable required interrupts */
- ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
-
- /* Configure interrupt aggregation */
- ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
-
if (hba->ufshcd_state == UFSHCD_STATE_RESET)
scsi_unblock_requests(hba->host);
hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
- scsi_scan_host(hba->host);
+
out:
return err;
}
@@ -1109,34 +1204,28 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
}
/**
- * ufshcd_initialize_hba - start the initialization process
+ * ufshcd_link_startup - Initialize unipro link startup
* @hba: per adapter instance
*
- * 1. Enable the controller via ufshcd_hba_enable.
- * 2. Program the Transfer Request List Address with the starting address of
- * UTRDL.
- * 3. Program the Task Management Request List Address with starting address
- * of UTMRDL.
- *
- * Returns 0 on success, non-zero value on failure.
+ * Returns 0 for success, non-zero in case of failure
*/
-static int ufshcd_initialize_hba(struct ufs_hba *hba)
+static int ufshcd_link_startup(struct ufs_hba *hba)
{
- if (ufshcd_hba_enable(hba))
- return -EIO;
+ int ret;
- /* Configure UTRL and UTMRL base address registers */
- ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
- REG_UTP_TRANSFER_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
- REG_UTP_TRANSFER_REQ_LIST_BASE_H);
- ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
- REG_UTP_TASK_REQ_LIST_BASE_L);
- ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
- REG_UTP_TASK_REQ_LIST_BASE_H);
+ /* enable UIC related interrupts */
+ ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
- /* Initialize unipro link startup procedure */
- return ufshcd_dme_link_startup(hba);
+ ret = ufshcd_dme_link_startup(hba);
+ if (ret)
+ goto out;
+
+ ret = ufshcd_make_hba_operational(hba);
+
+out:
+ if (ret)
+ dev_err(hba->dev, "link startup failed %d\n", ret);
+ return ret;
}
/**
@@ -1176,12 +1265,19 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
hba->outstanding_reqs = 0;
hba->outstanding_tasks = 0;
- /* start the initialization process */
- if (ufshcd_initialize_hba(hba)) {
+ /* Host controller enable */
+ if (ufshcd_hba_enable(hba)) {
dev_err(hba->dev,
"Reset: Controller initialization failed\n");
return FAILED;
}
+
+ if (ufshcd_link_startup(hba)) {
+ dev_err(hba->dev,
+ "Reset: Link start-up failed\n");
+ return FAILED;
+ }
+
return SUCCESS;
}
@@ -1434,6 +1530,19 @@ 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
+ */
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+{
+ if (hba->active_uic_cmd) {
+ hba->active_uic_cmd->argument2 |=
+ ufshcd_get_uic_cmd_result(hba);
+ complete(&hba->active_uic_cmd->done);
+ }
+}
+
+/**
* ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
*/
@@ -1473,28 +1582,6 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
}
/**
- * ufshcd_uic_cc_handler - handle UIC command completion
- * @work: pointer to a work queue structure
- *
- * Returns 0 on success, non-zero value on failure
- */
-static void ufshcd_uic_cc_handler (struct work_struct *work)
-{
- struct ufs_hba *hba;
-
- hba = container_of(work, struct ufs_hba, uic_workq);
-
- if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
- !(ufshcd_get_uic_cmd_result(hba))) {
-
- if (ufshcd_make_hba_operational(hba))
- dev_err(hba->dev,
- "cc: hba not operational state\n");
- return;
- }
-}
-
-/**
* ufshcd_fatal_err_handler - handle fatal errors
* @hba: per adapter instance
*/
@@ -1555,7 +1642,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
ufshcd_err_handler(hba);
if (intr_status & UIC_COMMAND_COMPL)
- schedule_work(&hba->uic_workq);
+ ufshcd_uic_cmd_compl(hba);
if (intr_status & UTP_TASK_REQ_COMPL)
ufshcd_tmc_handler(hba);
@@ -1778,6 +1865,21 @@ out:
return err;
}
+/**
+ * ufshcd_async_scan - asynchronous execution for link startup
+ * @data: data pointer to pass to this function
+ * @cookie: cookie data
+ */
+static void ufshcd_async_scan(void *data, async_cookie_t cookie)
+{
+ struct ufs_hba *hba = (struct ufs_hba *)data;
+ int ret;
+
+ ret = ufshcd_link_startup(hba);
+ if (!ret)
+ scsi_scan_host(hba->host);
+}
+
static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
@@ -1939,12 +2041,14 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
/* Initialize work queues */
- INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
/* Initialize mutex for query requests */
mutex_init(&hba->query.lock_ufs_query);
+ /* Initialize UIC command mutex */
+ mutex_init(&hba->uic_cmd_mutex);
+
/* IRQ registration */
err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
@@ -1965,14 +2069,17 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
goto out_free_irq;
}
- /* Initialization routine */
- err = ufshcd_initialize_hba(hba);
+ /* Host controller enable */
+ err = ufshcd_hba_enable(hba);
if (err) {
- dev_err(hba->dev, "Initialization failed\n");
+ dev_err(hba->dev, "Host controller enable failed\n");
goto out_remove_scsi_host;
}
+
*hba_handle = hba;
+ async_schedule(ufshcd_async_scan, hba);
+
return 0;
out_remove_scsi_host:
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index d98e046..974bd07 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -51,6 +51,7 @@
#include <linux/bitops.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -76,6 +77,7 @@
* @argument3: UIC command argument 3
* @cmd_active: Indicate if UIC command is outstanding
* @result: UIC command result
+ * @done: UIC command completion
*/
struct uic_command {
u32 command;
@@ -84,6 +86,7 @@ struct uic_command {
u32 argument3;
int cmd_active;
int result;
+ struct completion done;
};
/**
@@ -150,11 +153,11 @@ struct ufs_query {
* @ufs_version: UFS Version to which controller complies
* @irq: Irq number of the controller
* @active_uic_cmd: handle of active UIC command
+ * @uic_cmd_mutex: mutex for uic command
* @ufshcd_tm_wait_queue: wait queue for task management
* @tm_condition: condition variable for task management
* @ufshcd_state: UFSHCD states
* @intr_mask: Interrupt Mask Bits
- * @uic_workq: Work queue for UIC completion handling
* @feh_workq: Work queue for fatal controller error handling
* @errors: HBA errors
* @query: query request information
@@ -186,7 +189,9 @@ struct ufs_hba {
u32 ufs_version;
unsigned int irq;
- struct uic_command active_uic_cmd;
+ struct uic_command *active_uic_cmd;
+ struct mutex uic_cmd_mutex;
+
wait_queue_head_t ufshcd_tm_wait_queue;
unsigned long tm_condition;
@@ -194,7 +199,6 @@ struct ufs_hba {
u32 intr_mask;
/* Work Queues */
- struct work_struct uic_workq;
struct work_struct feh_workq;
/* HBA Errors */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (10 preceding siblings ...)
2013-05-08 8:42 ` [PATCH v4 4/6] scsi: ufs: rework link start-up process Seungwon Jeon
@ 2013-05-08 8:42 ` Seungwon Jeon
2013-05-09 6:53 ` Santosh Y
2013-05-08 8:43 ` [PATCH v4 6/6] scsi: ufs: add dme control primitives Seungwon Jeon
2013-05-10 10:42 ` [PATCH] scsi: ufs: use devres functions for ufshcd Seungwon Jeon
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-08 8:42 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Implements to support Get and Set operation of the DME.
These operations are used to configure the behavior of
the UNIPRO.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Tested-by: Maya Erez <merez@codeaurora.org>
---
Change in v4:
- Removed unipro.h header file. It will be introduced in next.
- Changed function names and error message.
drivers/scsi/ufs/ufshcd.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd.h | 30 +++++++++++++++
drivers/scsi/ufs/ufshci.h | 5 +++
3 files changed, 123 insertions(+), 0 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8363b92..e05eedb 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -191,6 +191,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
}
/**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+ return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
+/**
* ufshcd_free_hba_memory - Free allocated memory for LRB, request
* and task lists
* @hba: Pointer to adapter instance
@@ -1077,6 +1089,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
}
/**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val, u8 peer)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-set",
+ "dme-peer-set"
+ };
+ const char *set = action[!!peer];
+ int ret;
+
+ uic_cmd.command = peer ?
+ UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+ uic_cmd.argument1 = attr_sel;
+ uic_cmd.argument2 = UIC_ARG_ATTR_SET(attr_set);
+ uic_cmd.argument3 = mib_val;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret)
+ dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+ set, GET_UIC_ATTR_ID(attr_sel), ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate wherter peer or non-peer
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+ u32 *mib_val, u8 peer)
+{
+ struct uic_command uic_cmd = {0};
+ static const char *const action[] = {
+ "dme-get",
+ "dme-peer-get"
+ };
+ const char *get = action[!!peer];
+ int ret;
+
+ uic_cmd.command = peer ?
+ UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+ uic_cmd.argument1 = attr_sel;
+
+ ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+ if (ret) {
+ dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+ get, GET_UIC_ATTR_ID(attr_sel), ret);
+ goto out;
+ }
+
+ if (mib_val)
+ *mib_val = uic_cmd.argument3;
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
+
+/**
* ufshcd_make_hba_operational - Make UFS controller operational
* @hba: per adapter instance
*
@@ -1538,6 +1624,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
if (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);
}
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 974bd07..dabd29c 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -217,6 +217,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
unsigned int);
void ufshcd_remove(struct ufs_hba *);
+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);
+
/**
* ufshcd_hba_stop - Send controller to reset state
* @hba: per adapter instance
@@ -226,4 +231,29 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
}
+/* UIC command interfaces for DME primitives */
+static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val)
+{
+ return ufshcd_dme_set_attr(hba, attr_sel, attr_set, mib_val, 0);
+}
+
+static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
+ u8 attr_set, u32 mib_val)
+{
+ return ufshcd_dme_set_attr(hba, attr_sel, attr_set, mib_val, 1);
+}
+
+static inline int ufshcd_dme_get(struct ufs_hba *hba,
+ u32 attr_sel, u32 *mib_val)
+{
+ return ufshcd_dme_get_attr(hba, attr_sel, mib_val, 0);
+}
+
+static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
+ u32 attr_sel, u32 *mib_val)
+{
+ return ufshcd_dme_get_attr(hba, attr_sel, mib_val, 1);
+}
+
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f1e1b74..edb4d87 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -191,6 +191,11 @@ enum {
#define CONFIG_RESULT_CODE_MASK 0xFF
#define GENERIC_ERROR_CODE_MASK 0xFF
+#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
+ ((sel) & 0xFFFF))
+#define UIC_ARG_ATTR_SET(type) (((type) & 0xFF) << 16)
+#define GET_UIC_ATTR_ID(val) (((val) >> 16) & 0xFFFF)
+
/* UIC Commands */
enum {
UIC_CMD_DME_GET = 0x01,
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v4 6/6] scsi: ufs: add dme control primitives
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (11 preceding siblings ...)
2013-05-08 8:42 ` [PATCH v4 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
@ 2013-05-08 8:43 ` Seungwon Jeon
2013-05-09 6:53 ` Santosh Y
2013-05-10 10:42 ` [PATCH] scsi: ufs: use devres functions for ufshcd Seungwon Jeon
13 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-08 8:43 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
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
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
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
1 sibling, 0 replies; 52+ messages in thread
From: merez @ 2013-05-08 11:58 UTC (permalink / raw)
To: Seungwon Jeon
Cc: linux-scsi, 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Hi,
I tested the new set of patches (v4 1-6) and it works.
Thanks,
Maya
> Simplify operations with hiding mmio_base.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 105
> +++++++++++++++++++--------------------------
> drivers/scsi/ufs/ufshcd.h | 7 +++-
> 2 files changed, 50 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index f244812..cf7c8e4 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -71,7 +71,7 @@ enum {
> */
> static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UFS_VERSION);
> + return ufshcd_readl(hba, REG_UFS_VERSION);
> }
>
> /**
> @@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct
> ufs_hba *hba)
> */
> static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
> {
> - writel(~(1 << pos),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
> + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> }
>
> /**
> @@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
> */
> static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
> + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
> MASK_UIC_COMMAND_RESULT;
> }
>
> @@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int
> option)
> {
> switch (option) {
> case INT_AGGR_RESET:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_COUNTER_AND_TIMER_RESET),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE |
> + INT_AGGR_COUNTER_AND_TIMER_RESET,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> case INT_AGGR_CONFIG:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_PARAM_WRITE |
> - INT_AGGR_COUNTER_THRESHOLD_VALUE |
> - INT_AGGR_TIMEOUT_VALUE),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
> + INT_AGGR_COUNTER_THRESHOLD_VALUE |
> + INT_AGGR_TIMEOUT_VALUE,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> }
> }
> @@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int
> option)
> */
> static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> {
> - writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TASK_REQ_LIST_RUN_STOP));
> - writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
> + ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TASK_REQ_LIST_RUN_STOP);
> + ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
> }
>
> /**
> @@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba
> *hba)
> */
> static inline void ufshcd_hba_start(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
> }
>
> /**
> @@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba
> *hba)
> */
> static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
> {
> - return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> }
>
> /**
> @@ -299,8 +293,7 @@ static inline
> void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
> {
> __set_bit(task_tag, &hba->outstanding_reqs);
> - writel((1 << task_tag),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> }
>
> /**
> @@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
> */
> static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> {
> - hba->capabilities =
> - readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
> + hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
>
> /* nutrs and nutmrs are 0 based values */
> hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
> @@ -399,16 +391,13 @@ static inline void
> ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command
> *uic_cmnd)
> {
> /* Write Args */
> - writel(uic_cmnd->argument1,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
> - writel(uic_cmnd->argument2,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
> - writel(uic_cmnd->argument3,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
> + ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> + ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> + ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
>
> /* Write UIC Cmd */
> - writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
> - (hba->mmio_base + REG_UIC_COMMAND));
> + ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> + REG_UIC_COMMAND);
> }
>
> /**
> @@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba,
> u32 option)
> {
> switch (option) {
> case UFSHCD_INT_ENABLE:
> - writel(hba->int_enable_mask,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> break;
> case UFSHCD_INT_DISABLE:
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(INTERRUPT_DISABLE_MASK_10,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> + REG_INTERRUPT_ENABLE);
> else
> - writel(INTERRUPT_DISABLE_MASK_11,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> + REG_INTERRUPT_ENABLE);
> break;
> }
> }
> @@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba
> *hba)
> unsigned long flags;
>
> /* check if controller is ready to accept UIC commands */
> - if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
> + if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> UIC_COMMAND_READY) == 0x0) {
> dev_err(hba->dev,
> "Controller not ready"
> @@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba
> *hba)
> u32 reg;
>
> /* check if device present */
> - reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
> + reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
> if (!ufshcd_is_device_present(reg)) {
> dev_err(hba->dev, "cc: Device not present\n");
> err = -ENXIO;
> @@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba
> *hba)
> return -EIO;
>
> /* Configure UTRL and UTMRL base address registers */
> - writel(lower_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
> - writel(lower_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_H);
>
> /* Initialize unipro link startup procedure */
> return ufshcd_dme_link_startup(hba);
> @@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba
> *hba)
> int index;
>
> lrb = hba->lrb;
> - tr_doorbell =
> - readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
> + tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
>
> for (index = 0; index < hba->nutrs; index++) {
> @@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
> goto fatal_eh;
>
> if (hba->errors & UIC_ERROR) {
> -
> - reg = readl(hba->mmio_base +
> - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> goto fatal_eh;
> }
> @@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
> {
> u32 tm_doorbell;
>
> - tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
> + tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
> hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
> wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
> }
> @@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void
> *__hba)
> struct ufs_hba *hba = __hba;
>
> spin_lock(hba->host->host_lock);
> - intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
> + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
>
> if (intr_status) {
> ufshcd_sl_intr(hba, intr_status);
>
> /* If UFSHCI 1.0 then clear interrupt status register */
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(intr_status,
> - (hba->mmio_base + REG_INTERRUPT_STATUS));
> + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> retval = IRQ_HANDLED;
> }
> spin_unlock(hba->host->host_lock);
> @@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>
> /* send command to the controller */
> __set_bit(free_slot, &hba->outstanding_tasks);
> - writel((1 << free_slot),
> - (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
>
> spin_unlock_irqrestore(host->host_lock, flags);
>
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 336980b..6429bed 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -204,6 +204,11 @@ struct ufs_hba {
> struct ufs_query query;
> };
>
> +#define ufshcd_writel(hba, val, reg) \
> + writel((val), (hba)->mmio_base + (reg))
> +#define ufshcd_readl(hba, reg) \
> + readl((hba)->mmio_base + (reg))
> +
> int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
> @@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
> */
> static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> }
>
> #endif /* End of Header */
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
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
1 sibling, 1 reply; 52+ messages in thread
From: Santosh Y @ 2013-05-08 15:18 UTC (permalink / raw)
To: Seungwon Jeon, James E.J. Bottomley; +Cc: linux-scsi, Vinayak Holikatti
On Wed, May 8, 2013 at 2:11 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Simplify operations with hiding mmio_base.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 105 +++++++++++++++++++--------------------------
> drivers/scsi/ufs/ufshcd.h | 7 +++-
> 2 files changed, 50 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index f244812..cf7c8e4 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -71,7 +71,7 @@ enum {
> */
> static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UFS_VERSION);
> + return ufshcd_readl(hba, REG_UFS_VERSION);
> }
>
> /**
> @@ -130,8 +130,7 @@ static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
> */
> static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos)
> {
> - writel(~(1 << pos),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR));
> + ufshcd_writel(hba, ~(1 << pos), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> }
>
> /**
> @@ -165,7 +164,7 @@ static inline int ufshcd_get_lists_status(u32 reg)
> */
> static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> {
> - return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) &
> + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) &
> MASK_UIC_COMMAND_RESULT;
> }
>
> @@ -238,18 +237,15 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
> {
> switch (option) {
> case INT_AGGR_RESET:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_COUNTER_AND_TIMER_RESET),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE |
> + INT_AGGR_COUNTER_AND_TIMER_RESET,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> case INT_AGGR_CONFIG:
> - writel((INT_AGGR_ENABLE |
> - INT_AGGR_PARAM_WRITE |
> - INT_AGGR_COUNTER_THRESHOLD_VALUE |
> - INT_AGGR_TIMEOUT_VALUE),
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL));
> + ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
> + INT_AGGR_COUNTER_THRESHOLD_VALUE |
> + INT_AGGR_TIMEOUT_VALUE,
> + REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
> break;
> }
> }
> @@ -262,12 +258,10 @@ ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
> */
> static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> {
> - writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TASK_REQ_LIST_RUN_STOP));
> - writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> - (hba->mmio_base +
> - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP));
> + ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TASK_REQ_LIST_RUN_STOP);
> + ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT,
> + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP);
> }
>
> /**
> @@ -276,7 +270,7 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
> */
> static inline void ufshcd_hba_start(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE);
> }
>
> /**
> @@ -287,7 +281,7 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
> */
> static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
> {
> - return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
> }
>
> /**
> @@ -299,8 +293,7 @@ static inline
> void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
> {
> __set_bit(task_tag, &hba->outstanding_reqs);
> - writel((1 << task_tag),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> }
>
> /**
> @@ -381,8 +374,7 @@ void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
> */
> static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> {
> - hba->capabilities =
> - readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES);
> + hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES);
>
> /* nutrs and nutmrs are 0 based values */
> hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1;
> @@ -399,16 +391,13 @@ static inline void
> ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> {
> /* Write Args */
> - writel(uic_cmnd->argument1,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_1));
> - writel(uic_cmnd->argument2,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_2));
> - writel(uic_cmnd->argument3,
> - (hba->mmio_base + REG_UIC_COMMAND_ARG_3));
> + ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> + ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> + ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
>
> /* Write UIC Cmd */
> - writel((uic_cmnd->command & COMMAND_OPCODE_MASK),
> - (hba->mmio_base + REG_UIC_COMMAND));
> + ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> + REG_UIC_COMMAND);
> }
>
> /**
> @@ -460,16 +449,15 @@ static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
> {
> switch (option) {
> case UFSHCD_INT_ENABLE:
> - writel(hba->int_enable_mask,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> break;
> case UFSHCD_INT_DISABLE:
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(INTERRUPT_DISABLE_MASK_10,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> + REG_INTERRUPT_ENABLE);
> else
> - writel(INTERRUPT_DISABLE_MASK_11,
> - (hba->mmio_base + REG_INTERRUPT_ENABLE));
> + ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> + REG_INTERRUPT_ENABLE);
> break;
> }
> }
> @@ -940,7 +928,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> unsigned long flags;
>
> /* check if controller is ready to accept UIC commands */
> - if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) &
> + if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> UIC_COMMAND_READY) == 0x0) {
> dev_err(hba->dev,
> "Controller not ready"
> @@ -985,7 +973,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> u32 reg;
>
> /* check if device present */
> - reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS));
> + reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS);
> if (!ufshcd_is_device_present(reg)) {
> dev_err(hba->dev, "cc: Device not present\n");
> err = -ENXIO;
> @@ -1107,14 +1095,14 @@ static int ufshcd_initialize_hba(struct ufs_hba *hba)
> return -EIO;
>
> /* Configure UTRL and UTMRL base address registers */
> - writel(lower_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H));
> - writel(lower_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L));
> - writel(upper_32_bits(hba->utmrdl_dma_addr),
> - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H));
> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_H);
>
> /* Initialize unipro link startup procedure */
> return ufshcd_dme_link_startup(hba);
> @@ -1427,8 +1415,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
> int index;
>
> lrb = hba->lrb;
> - tr_doorbell =
> - readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL);
> + tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
> completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
>
> for (index = 0; index < hba->nutrs; index++) {
> @@ -1502,9 +1489,7 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
> goto fatal_eh;
>
> if (hba->errors & UIC_ERROR) {
> -
> - reg = readl(hba->mmio_base +
> - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> + reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
> if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
> goto fatal_eh;
> }
> @@ -1522,7 +1507,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
> {
> u32 tm_doorbell;
>
> - tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL);
> + tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
> hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
> wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
> }
> @@ -1563,15 +1548,14 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
> struct ufs_hba *hba = __hba;
>
> spin_lock(hba->host->host_lock);
> - intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS);
> + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
>
> if (intr_status) {
> ufshcd_sl_intr(hba, intr_status);
>
> /* If UFSHCI 1.0 then clear interrupt status register */
> if (hba->ufs_version == UFSHCI_VERSION_10)
> - writel(intr_status,
> - (hba->mmio_base + REG_INTERRUPT_STATUS));
> + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> retval = IRQ_HANDLED;
> }
> spin_unlock(hba->host->host_lock);
> @@ -1636,8 +1620,7 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>
> /* send command to the controller */
> __set_bit(free_slot, &hba->outstanding_tasks);
> - writel((1 << free_slot),
> - (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL));
> + ufshcd_writel(hba, 1 << free_slot, REG_UTP_TASK_REQ_DOOR_BELL);
>
> spin_unlock_irqrestore(host->host_lock, flags);
>
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 336980b..6429bed 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -204,6 +204,11 @@ struct ufs_hba {
> struct ufs_query query;
> };
>
> +#define ufshcd_writel(hba, val, reg) \
> + writel((val), (hba)->mmio_base + (reg))
> +#define ufshcd_readl(hba, reg) \
> + readl((hba)->mmio_base + (reg))
> +
> int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
> @@ -214,7 +219,7 @@ void ufshcd_remove(struct ufs_hba *);
> */
> static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> {
> - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE));
> + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> }
>
> #endif /* End of Header */
> --
> 1.7.0.4
>
Hi Seungwon,
I could apply your test patch without any issues but I still get
"fatal: cannot convert from ks_c_5601-1987 to UTF-8" with V4 patch
series.
At this point I'm confused :-| not sure if the problem is the
character set or something else...
Hi James,
Please consider Acked-by: Santosh Y <santoshsy@gmail.com>, if you are
able to apply the patches.
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 2/6] scsi: ufs: amend interrupt configuration
2013-05-08 8:41 ` [PATCH v4 2/6] scsi: ufs: amend interrupt configuration Seungwon Jeon
@ 2013-05-08 15:19 ` Santosh Y
0 siblings, 0 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-08 15:19 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Wed, May 8, 2013 at 2:11 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> It makes interrupt setting more flexible especially
> for disabling. And wrong bit mask is fixed for ver 1.0.
> [17:16] is added for mask.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 84 +++++++++++++++++++++++++++++++-------------
> drivers/scsi/ufs/ufshcd.h | 4 +-
> drivers/scsi/ufs/ufshci.h | 5 ++-
> 3 files changed, 64 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index cf7c8e4..feaf221 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -35,6 +35,10 @@
>
> #include "ufshcd.h"
>
> +#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
> + UTP_TASK_REQ_COMPL |\
> + UFSHCD_ERROR_MASK)
> +
> enum {
> UFSHCD_MAX_CHANNEL = 0,
> UFSHCD_MAX_ID = 1,
> @@ -64,6 +68,20 @@ enum {
> };
>
> /**
> + * ufshcd_get_intr_mask - Get the interrupt bit mask
> + * @hba - Pointer to adapter instance
> + *
> + * Returns interrupt bit mask per version
> + */
> +static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
> +{
> + if (hba->ufs_version == UFSHCI_VERSION_10)
> + return INTERRUPT_MASK_ALL_VER_10;
> + else
> + return INTERRUPT_MASK_ALL_VER_11;
> +}
> +
> +/**
> * ufshcd_get_ufs_version - Get the UFS version supported by the HBA
> * @hba - Pointer to adapter instance
> *
> @@ -441,25 +459,45 @@ static int ufshcd_map_sg(struct ufshcd_lrb *lrbp)
> }
>
> /**
> - * ufshcd_int_config - enable/disable interrupts
> + * ufshcd_enable_intr - enable interrupts
> * @hba: per adapter instance
> - * @option: interrupt option
> + * @intrs: interrupt bits
> */
> -static void ufshcd_int_config(struct ufs_hba *hba, u32 option)
> +static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs)
> {
> - switch (option) {
> - case UFSHCD_INT_ENABLE:
> - ufshcd_writel(hba, hba->int_enable_mask, REG_INTERRUPT_ENABLE);
> - break;
> - case UFSHCD_INT_DISABLE:
> - if (hba->ufs_version == UFSHCI_VERSION_10)
> - ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_10,
> - REG_INTERRUPT_ENABLE);
> - else
> - ufshcd_writel(hba, INTERRUPT_DISABLE_MASK_11,
> - REG_INTERRUPT_ENABLE);
> - break;
> + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
> +
> + if (hba->ufs_version == UFSHCI_VERSION_10) {
> + u32 rw;
> + rw = set & INTERRUPT_MASK_RW_VER_10;
> + set = rw | ((set ^ intrs) & intrs);
> + } else {
> + set |= intrs;
> + }
> +
> + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
> +}
> +
> +/**
> + * ufshcd_disable_intr - disable interrupts
> + * @hba: per adapter instance
> + * @intrs: interrupt bits
> + */
> +static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
> +{
> + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
> +
> + if (hba->ufs_version == UFSHCI_VERSION_10) {
> + u32 rw;
> + rw = (set & INTERRUPT_MASK_RW_VER_10) &
> + ~(intrs & INTERRUPT_MASK_RW_VER_10);
> + set = rw | ((set & intrs) & ~INTERRUPT_MASK_RW_VER_10);
> +
> + } else {
> + set &= ~intrs;
> }
> +
> + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
> }
>
> /**
> @@ -946,8 +984,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> uic_cmd->argument3 = 0;
>
> /* enable UIC related interrupts */
> - hba->int_enable_mask |= UIC_COMMAND_COMPL;
> - ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
> + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>
> /* sending UIC commands to controller */
> ufshcd_send_uic_command(hba, uic_cmd);
> @@ -994,13 +1031,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> }
>
> /* Enable required interrupts */
> - hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL |
> - UIC_ERROR |
> - UTP_TASK_REQ_COMPL |
> - DEVICE_FATAL_ERROR |
> - CONTROLLER_FATAL_ERROR |
> - SYSTEM_BUS_FATAL_ERROR);
> - ufshcd_int_config(hba, UFSHCD_INT_ENABLE);
> + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
>
> /* Configure interrupt aggregation */
> ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> @@ -1828,7 +1859,7 @@ static void ufshcd_hba_free(struct ufs_hba *hba)
> void ufshcd_remove(struct ufs_hba *hba)
> {
> /* disable interrupts */
> - ufshcd_int_config(hba, UFSHCD_INT_DISABLE);
> + ufshcd_disable_intr(hba, hba->intr_mask);
>
> ufshcd_hba_stop(hba);
> ufshcd_hba_free(hba);
> @@ -1886,6 +1917,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> /* Get UFS version supported by the controller */
> hba->ufs_version = ufshcd_get_ufs_version(hba);
>
> + /* Get Interrupt bit mask per version */
> + hba->intr_mask = ufshcd_get_intr_mask(hba);
> +
> /* Allocate memory for host memory space */
> err = ufshcd_memory_alloc(hba);
> if (err) {
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 6429bed..d98e046 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -153,7 +153,7 @@ struct ufs_query {
> * @ufshcd_tm_wait_queue: wait queue for task management
> * @tm_condition: condition variable for task management
> * @ufshcd_state: UFSHCD states
> - * @int_enable_mask: Interrupt Mask Bits
> + * @intr_mask: Interrupt Mask Bits
> * @uic_workq: Work queue for UIC completion handling
> * @feh_workq: Work queue for fatal controller error handling
> * @errors: HBA errors
> @@ -191,7 +191,7 @@ struct ufs_hba {
> unsigned long tm_condition;
>
> u32 ufshcd_state;
> - u32 int_enable_mask;
> + u32 intr_mask;
>
> /* Work Queues */
> struct work_struct uic_workq;
> diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
> index 4a86247..f1e1b74 100644
> --- a/drivers/scsi/ufs/ufshci.h
> +++ b/drivers/scsi/ufs/ufshci.h
> @@ -232,10 +232,11 @@ enum {
> /* Interrupt disable masks */
> enum {
> /* Interrupt disable mask for UFSHCI v1.0 */
> - INTERRUPT_DISABLE_MASK_10 = 0xFFFF,
> + INTERRUPT_MASK_ALL_VER_10 = 0x30FFF,
> + INTERRUPT_MASK_RW_VER_10 = 0x30000,
>
> /* Interrupt disable mask for UFSHCI v1.1 */
> - INTERRUPT_DISABLE_MASK_11 = 0x0,
> + INTERRUPT_MASK_ALL_VER_11 = 0x31FFF,
> };
>
> /*
> --
> 1.7.0.4
>
>
Acked-by: Santosh Y <santoshsy@gmail.com>
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 3/6] scsi: ufs: fix interrupt status clears
2013-05-08 8:41 ` [PATCH v4 3/6] scsi: ufs: fix interrupt status clears Seungwon Jeon
@ 2013-05-08 15:19 ` Santosh Y
0 siblings, 0 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-08 15:19 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Wed, May 8, 2013 at 2:11 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> There is no need to check the version to clear
> the interrupt status. And the order is changed
> prior to actual handling.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> drivers/scsi/ufs/ufshcd.c | 5 +----
> 1 files changed, 1 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index feaf221..e04c74e 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -1582,11 +1582,8 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
> intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
>
> if (intr_status) {
> + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> ufshcd_sl_intr(hba, intr_status);
> -
> - /* If UFSHCI 1.0 then clear interrupt status register */
> - if (hba->ufs_version == UFSHCI_VERSION_10)
> - ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
> retval = IRQ_HANDLED;
> }
> spin_unlock(hba->host->host_lock);
> --
> 1.7.0.4
>
>
Acked-by: Santosh Y <santoshsy@gmail.com>
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 4/6] scsi: ufs: rework link start-up process
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
0 siblings, 0 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-08 15:20 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Wed, May 8, 2013 at 2:12 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Link start-up requires long time with multiphase handshakes
> between UFS host and device. This affects driver's probe time.
> This patch let link start-up run asynchronously. Link start-up
> will be executed at the end of prove separately.
> Along with this change, the following is worked.
>
> Defined completion time of uic command to avoid a permanent wait.
> Added mutex to guarantee of uic command at a time.
> Adapted some sequence of controller initialization after link statup
> according to HCI standard.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> Change in v4:
> - Addressed late interrupt case (Sujit).
> - Move print message in link startup (Maya).
>
> drivers/scsi/ufs/ufshcd.c | 295 ++++++++++++++++++++++++++++++--------------
> drivers/scsi/ufs/ufshcd.h | 10 +-
> 2 files changed, 208 insertions(+), 97 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index e04c74e..8363b92 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -33,11 +33,15 @@
> * this program.
> */
>
> +#include <linux/async.h>
> +
> #include "ufshcd.h"
>
> #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
> UTP_TASK_REQ_COMPL |\
> UFSHCD_ERROR_MASK)
> +/* UIC command timeout, unit: ms */
> +#define UIC_CMD_TIMEOUT 500
>
> enum {
> UFSHCD_MAX_CHANNEL = 0,
> @@ -401,24 +405,122 @@ static inline void ufshcd_hba_capabilities(struct ufs_hba *hba)
> }
>
> /**
> - * ufshcd_send_uic_command - Send UIC commands to unipro layers
> + * ufshcd_ready_for_uic_cmd - Check if controller is ready
> + * to accept UIC commands
> * @hba: per adapter instance
> - * @uic_command: UIC command
> + * Return true on success, else false
> + */
> +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
> +{
> + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
> + return true;
> + else
> + return false;
> +}
> +
> +/**
> + * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
> + * @hba: per adapter instance
> + * @uic_cmd: UIC command
> + *
> + * Mutex must be held.
> */
> static inline void
> -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd)
> +ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> {
> + WARN_ON(hba->active_uic_cmd);
> +
> + hba->active_uic_cmd = uic_cmd;
> +
> /* Write Args */
> - ufshcd_writel(hba, uic_cmnd->argument1, REG_UIC_COMMAND_ARG_1);
> - ufshcd_writel(hba, uic_cmnd->argument2, REG_UIC_COMMAND_ARG_2);
> - ufshcd_writel(hba, uic_cmnd->argument3, REG_UIC_COMMAND_ARG_3);
> + ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1);
> + ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2);
> + ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3);
>
> /* Write UIC Cmd */
> - ufshcd_writel(hba, uic_cmnd->command & COMMAND_OPCODE_MASK,
> + ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
> REG_UIC_COMMAND);
> }
>
> /**
> + * ufshcd_wait_for_uic_cmd - Wait complectioin of UIC command
> + * @hba: per adapter instance
> + * @uic_command: UIC command
> + *
> + * Must be called with mutex held.
> + * Returns 0 only if success.
> + */
> +static int
> +ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> +{
> + int ret;
> + unsigned long flags;
> +
> + if (wait_for_completion_timeout(&uic_cmd->done,
> + msecs_to_jiffies(UIC_CMD_TIMEOUT)))
> + ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
> + else
> + ret = -ETIMEDOUT;
> +
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + hba->active_uic_cmd = NULL;
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + return ret;
> +}
> +
> +/**
> + * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
> + * @hba: per adapter instance
> + * @uic_cmd: UIC command
> + *
> + * Identical to ufshcd_send_uic_cmd() expect mutex. Must be called
> + * with mutex held.
> + * Returns 0 only if success.
> + */
> +static int
> +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> +{
> + int ret;
> + unsigned long flags;
> +
> + if (!ufshcd_ready_for_uic_cmd(hba)) {
> + dev_err(hba->dev,
> + "Controller not ready to accept UIC commands\n");
> + return -EIO;
> + }
> +
> + init_completion(&uic_cmd->done);
> +
> + spin_lock_irqsave(hba->host->host_lock, flags);
> + ufshcd_dispatch_uic_cmd(hba, uic_cmd);
> + spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd);
> +
> + return ret;
> +}
> +
> +/**
> + * ufshcd_send_uic_cmd - Send UIC commands and retrieve the result
> + * @hba: per adapter instance
> + * @uic_cmd: UIC command
> + *
> + * Returns 0 only if success.
> + */
> +static int
> +ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
> +{
> + int ret;
> +
> + mutex_lock(&hba->uic_cmd_mutex);
> + ret = __ufshcd_send_uic_cmd(hba, uic_cmd);
> + mutex_unlock(&hba->uic_cmd_mutex);
> +
> + return ret;
> +}
> +
> +/**
> * ufshcd_map_sg - Map scatter-gather list to prdt
> * @lrbp - pointer to local reference block
> *
> @@ -962,34 +1064,16 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
> */
> static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> {
> - struct uic_command *uic_cmd;
> - unsigned long flags;
> -
> - /* check if controller is ready to accept UIC commands */
> - if ((ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
> - UIC_COMMAND_READY) == 0x0) {
> - dev_err(hba->dev,
> - "Controller not ready"
> - " to accept UIC commands\n");
> - return -EIO;
> - }
> + struct uic_command uic_cmd = {0};
> + int ret;
>
> - spin_lock_irqsave(hba->host->host_lock, flags);
> + uic_cmd.command = UIC_CMD_DME_LINK_STARTUP;
>
> - /* form UIC command */
> - uic_cmd = &hba->active_uic_cmd;
> - uic_cmd->command = UIC_CMD_DME_LINK_STARTUP;
> - uic_cmd->argument1 = 0;
> - uic_cmd->argument2 = 0;
> - uic_cmd->argument3 = 0;
> -
> - /* enable UIC related interrupts */
> - ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
> -
> - /* sending UIC commands to controller */
> - ufshcd_send_uic_command(hba, uic_cmd);
> - spin_unlock_irqrestore(hba->host->host_lock, flags);
> - return 0;
> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> + if (ret)
> + dev_err(hba->dev,
> + "dme-link-startup: error code %d\n", ret);
> + return ret;
> }
>
> /**
> @@ -998,9 +1082,10 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> *
> * To bring UFS host controller to operational state,
> * 1. Check if device is present
> - * 2. Configure run-stop-registers
> - * 3. Enable required interrupts
> - * 4. Configure interrupt aggregation
> + * 2. Enable required interrupts
> + * 3. Configure interrupt aggregation
> + * 4. Program UTRL and UTMRL base addres
> + * 5. Configure run-stop-registers
> *
> * Returns 0 on success, non-zero value on failure
> */
> @@ -1017,6 +1102,22 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> goto out;
> }
>
> + /* Enable required interrupts */
> + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
> +
> + /* Configure interrupt aggregation */
> + ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> +
> + /* Configure UTRL and UTMRL base address registers */
> + ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> + REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> + ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_L);
> + ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> + REG_UTP_TASK_REQ_LIST_BASE_H);
> +
> /*
> * UCRDY, UTMRLDY and UTRLRDY bits must be 1
> * DEI, HEI bits must be 0
> @@ -1030,17 +1131,11 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
> goto out;
> }
>
> - /* Enable required interrupts */
> - ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
> -
> - /* Configure interrupt aggregation */
> - ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
> -
> if (hba->ufshcd_state == UFSHCD_STATE_RESET)
> scsi_unblock_requests(hba->host);
>
> hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
> - scsi_scan_host(hba->host);
> +
> out:
> return err;
> }
> @@ -1109,34 +1204,28 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
> }
>
> /**
> - * ufshcd_initialize_hba - start the initialization process
> + * ufshcd_link_startup - Initialize unipro link startup
> * @hba: per adapter instance
> *
> - * 1. Enable the controller via ufshcd_hba_enable.
> - * 2. Program the Transfer Request List Address with the starting address of
> - * UTRDL.
> - * 3. Program the Task Management Request List Address with starting address
> - * of UTMRDL.
> - *
> - * Returns 0 on success, non-zero value on failure.
> + * Returns 0 for success, non-zero in case of failure
> */
> -static int ufshcd_initialize_hba(struct ufs_hba *hba)
> +static int ufshcd_link_startup(struct ufs_hba *hba)
> {
> - if (ufshcd_hba_enable(hba))
> - return -EIO;
> + int ret;
>
> - /* Configure UTRL and UTMRL base address registers */
> - ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
> - REG_UTP_TRANSFER_REQ_LIST_BASE_L);
> - ufshcd_writel(hba, upper_32_bits(hba->utrdl_dma_addr),
> - REG_UTP_TRANSFER_REQ_LIST_BASE_H);
> - ufshcd_writel(hba, lower_32_bits(hba->utmrdl_dma_addr),
> - REG_UTP_TASK_REQ_LIST_BASE_L);
> - ufshcd_writel(hba, upper_32_bits(hba->utmrdl_dma_addr),
> - REG_UTP_TASK_REQ_LIST_BASE_H);
> + /* enable UIC related interrupts */
> + ufshcd_enable_intr(hba, UIC_COMMAND_COMPL);
>
> - /* Initialize unipro link startup procedure */
> - return ufshcd_dme_link_startup(hba);
> + ret = ufshcd_dme_link_startup(hba);
> + if (ret)
> + goto out;
> +
> + ret = ufshcd_make_hba_operational(hba);
> +
> +out:
> + if (ret)
> + dev_err(hba->dev, "link startup failed %d\n", ret);
> + return ret;
> }
>
> /**
> @@ -1176,12 +1265,19 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
> hba->outstanding_reqs = 0;
> hba->outstanding_tasks = 0;
>
> - /* start the initialization process */
> - if (ufshcd_initialize_hba(hba)) {
> + /* Host controller enable */
> + if (ufshcd_hba_enable(hba)) {
> dev_err(hba->dev,
> "Reset: Controller initialization failed\n");
> return FAILED;
> }
> +
> + if (ufshcd_link_startup(hba)) {
> + dev_err(hba->dev,
> + "Reset: Link start-up failed\n");
> + return FAILED;
> + }
> +
> return SUCCESS;
> }
>
> @@ -1434,6 +1530,19 @@ 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
> + */
> +static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
> +{
> + if (hba->active_uic_cmd) {
> + hba->active_uic_cmd->argument2 |=
> + ufshcd_get_uic_cmd_result(hba);
> + complete(&hba->active_uic_cmd->done);
> + }
> +}
> +
> +/**
> * ufshcd_transfer_req_compl - handle SCSI and query command completion
> * @hba: per adapter instance
> */
> @@ -1473,28 +1582,6 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
> }
>
> /**
> - * ufshcd_uic_cc_handler - handle UIC command completion
> - * @work: pointer to a work queue structure
> - *
> - * Returns 0 on success, non-zero value on failure
> - */
> -static void ufshcd_uic_cc_handler (struct work_struct *work)
> -{
> - struct ufs_hba *hba;
> -
> - hba = container_of(work, struct ufs_hba, uic_workq);
> -
> - if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) &&
> - !(ufshcd_get_uic_cmd_result(hba))) {
> -
> - if (ufshcd_make_hba_operational(hba))
> - dev_err(hba->dev,
> - "cc: hba not operational state\n");
> - return;
> - }
> -}
> -
> -/**
> * ufshcd_fatal_err_handler - handle fatal errors
> * @hba: per adapter instance
> */
> @@ -1555,7 +1642,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
> ufshcd_err_handler(hba);
>
> if (intr_status & UIC_COMMAND_COMPL)
> - schedule_work(&hba->uic_workq);
> + ufshcd_uic_cmd_compl(hba);
>
> if (intr_status & UTP_TASK_REQ_COMPL)
> ufshcd_tmc_handler(hba);
> @@ -1778,6 +1865,21 @@ out:
> return err;
> }
>
> +/**
> + * ufshcd_async_scan - asynchronous execution for link startup
> + * @data: data pointer to pass to this function
> + * @cookie: cookie data
> + */
> +static void ufshcd_async_scan(void *data, async_cookie_t cookie)
> +{
> + struct ufs_hba *hba = (struct ufs_hba *)data;
> + int ret;
> +
> + ret = ufshcd_link_startup(hba);
> + if (!ret)
> + scsi_scan_host(hba->host);
> +}
> +
> static struct scsi_host_template ufshcd_driver_template = {
> .module = THIS_MODULE,
> .name = UFSHCD,
> @@ -1939,12 +2041,14 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
>
> /* Initialize work queues */
> - INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler);
> INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
>
> /* Initialize mutex for query requests */
> mutex_init(&hba->query.lock_ufs_query);
>
> + /* Initialize UIC command mutex */
> + mutex_init(&hba->uic_cmd_mutex);
> +
> /* IRQ registration */
> err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
> if (err) {
> @@ -1965,14 +2069,17 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> goto out_free_irq;
> }
>
> - /* Initialization routine */
> - err = ufshcd_initialize_hba(hba);
> + /* Host controller enable */
> + err = ufshcd_hba_enable(hba);
> if (err) {
> - dev_err(hba->dev, "Initialization failed\n");
> + dev_err(hba->dev, "Host controller enable failed\n");
> goto out_remove_scsi_host;
> }
> +
> *hba_handle = hba;
>
> + async_schedule(ufshcd_async_scan, hba);
> +
> return 0;
>
> out_remove_scsi_host:
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index d98e046..974bd07 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -51,6 +51,7 @@
> #include <linux/bitops.h>
> #include <linux/pm_runtime.h>
> #include <linux/clk.h>
> +#include <linux/completion.h>
>
> #include <asm/irq.h>
> #include <asm/byteorder.h>
> @@ -76,6 +77,7 @@
> * @argument3: UIC command argument 3
> * @cmd_active: Indicate if UIC command is outstanding
> * @result: UIC command result
> + * @done: UIC command completion
> */
> struct uic_command {
> u32 command;
> @@ -84,6 +86,7 @@ struct uic_command {
> u32 argument3;
> int cmd_active;
> int result;
> + struct completion done;
> };
>
> /**
> @@ -150,11 +153,11 @@ struct ufs_query {
> * @ufs_version: UFS Version to which controller complies
> * @irq: Irq number of the controller
> * @active_uic_cmd: handle of active UIC command
> + * @uic_cmd_mutex: mutex for uic command
> * @ufshcd_tm_wait_queue: wait queue for task management
> * @tm_condition: condition variable for task management
> * @ufshcd_state: UFSHCD states
> * @intr_mask: Interrupt Mask Bits
> - * @uic_workq: Work queue for UIC completion handling
> * @feh_workq: Work queue for fatal controller error handling
> * @errors: HBA errors
> * @query: query request information
> @@ -186,7 +189,9 @@ struct ufs_hba {
> u32 ufs_version;
> unsigned int irq;
>
> - struct uic_command active_uic_cmd;
> + struct uic_command *active_uic_cmd;
> + struct mutex uic_cmd_mutex;
> +
> wait_queue_head_t ufshcd_tm_wait_queue;
> unsigned long tm_condition;
>
> @@ -194,7 +199,6 @@ struct ufs_hba {
> u32 intr_mask;
>
> /* Work Queues */
> - struct work_struct uic_workq;
> struct work_struct feh_workq;
>
> /* HBA Errors */
> --
> 1.7.0.4
>
>
Acked-by: Santosh Y <santoshsy@gmail.com>
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-08 15:18 ` Santosh Y
@ 2013-05-09 1:59 ` Seungwon Jeon
2013-05-09 3:27 ` Santosh Y
0 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-09 1:59 UTC (permalink / raw)
To: 'Santosh Y', 'James E.J. Bottomley'
Cc: linux-scsi, 'Vinayak Holikatti'
On Thursday, May 09, 2013, Santosh Y wrote:
> On Wed, May 8, 2013 at 2:11 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > Simplify operations with hiding mmio_base.
> >
> > Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> > Tested-by: Maya Erez <merez@codeaurora.org>
> > ---
> > drivers/scsi/ufs/ufshcd.c | 105 +++++++++++++++++++--------------------------
> > drivers/scsi/ufs/ufshcd.h | 7 +++-
> > 2 files changed, 50 insertions(+), 62 deletions(-)
> >
> Hi Seungwon,
> I could apply your test patch without any issues but I still get
> "fatal: cannot convert from ks_c_5601-1987 to UTF-8" with V4 patch
> series.
> At this point I'm confused :-| not sure if the problem is the
> character set or something else...
Hi Santosh,
You got a pass with my test one before v4. It's strange.
Hi James,
Please let me know, if you have a same problem.
I guess I should change mail sender.
>
>
> Hi James,
> Please consider Acked-by: Santosh Y <santoshsy@gmail.com>, if you are
> able to apply the patches.
Thank you for your ack.
There are two patches remained. These are applied with your final comments.
Do you have any idea?
[PATCH v4 5/6] scsi: ufs: add dme configuration primitives
[PATCH v4 6/6] scsi: ufs: add dme control primitives
Thanks,
Seungwon Jeon
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-09 1:59 ` Seungwon Jeon
@ 2013-05-09 3:27 ` Santosh Y
2013-05-09 6:39 ` Seungwon Jeon
0 siblings, 1 reply; 52+ messages in thread
From: Santosh Y @ 2013-05-09 3:27 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: James E.J. Bottomley, linux-scsi, Vinayak Holikatti
> There are two patches remained. These are applied with your final comments.
> Do you have any idea?
> [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
> [PATCH v4 6/6] scsi: ufs: add dme control primitives
>
Since there is no use case for these implementations yet, except for
ufshcd_get_dme_attr_val(), as per James's suggestion
[http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg20207.html]
I did not ACK the patches.
The same patches can be used to implement related features and resubmit later.
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-09 3:27 ` Santosh Y
@ 2013-05-09 6:39 ` Seungwon Jeon
2013-05-09 6:52 ` Santosh Y
0 siblings, 1 reply; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-09 6:39 UTC (permalink / raw)
To: 'Santosh Y'
Cc: 'James E.J. Bottomley', linux-scsi,
'Vinayak Holikatti'
On Thursday, May 09, 2013 Santosh wrote:
> > There are two patches remained. These are applied with your final comments.
> > Do you have any idea?
> > [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
> > [PATCH v4 6/6] scsi: ufs: add dme control primitives
> >
>
> Since there is no use case for these implementations yet, except for
> ufshcd_get_dme_attr_val(), as per James's suggestion
> [http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg20207.html]
> I did not ACK the patches.
> The same patches can be used to implement related features and resubmit later.
I respect your decision. But I have another opinion.
The remained patches are basic operations which should be supported by ufshcd.
Especially, dme_set/set will be used in vender specific part of host controller rather than in ufshcd itself.
And above all, Maya Erez completed to test and reported working fine.
If these patches are merged this time, it would be helpful to various hosts.
Thanks,
Seungwon Jeon
>
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-09 6:39 ` Seungwon Jeon
@ 2013-05-09 6:52 ` Santosh Y
2013-05-09 14:21 ` James Bottomley
0 siblings, 1 reply; 52+ messages in thread
From: Santosh Y @ 2013-05-09 6:52 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: James E.J. Bottomley, linux-scsi, Vinayak Holikatti
On Thu, May 9, 2013 at 12:09 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> On Thursday, May 09, 2013 Santosh wrote:
>> > There are two patches remained. These are applied with your final comments.
>> > Do you have any idea?
>> > [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
>> > [PATCH v4 6/6] scsi: ufs: add dme control primitives
>> >
>>
>> Since there is no use case for these implementations yet, except for
>> ufshcd_get_dme_attr_val(), as per James's suggestion
>> [http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg20207.html]
>> I did not ACK the patches.
>> The same patches can be used to implement related features and resubmit later.
> I respect your decision. But I have another opinion.
> The remained patches are basic operations which should be supported by ufshcd.
> Especially, dme_set/set will be used in vender specific part of host controller rather than in ufshcd itself.
> And above all, Maya Erez completed to test and reported working fine.
> If these patches are merged this time, it would be helpful to various hosts.
>
I'm ok with merging these patches if James is fine with it. I will ACK
the patches.
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
2013-05-08 8:42 ` [PATCH v4 5/6] scsi: ufs: add dme configuration primitives Seungwon Jeon
@ 2013-05-09 6:53 ` Santosh Y
0 siblings, 0 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-09 6:53 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Wed, May 8, 2013 at 2:12 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Implements to support Get and Set operation of the DME.
> These operations are used to configure the behavior of
> the UNIPRO.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Tested-by: Maya Erez <merez@codeaurora.org>
> ---
> Change in v4:
> - Removed unipro.h header file. It will be introduced in next.
> - Changed function names and error message.
>
> drivers/scsi/ufs/ufshcd.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
> drivers/scsi/ufs/ufshcd.h | 30 +++++++++++++++
> drivers/scsi/ufs/ufshci.h | 5 +++
> 3 files changed, 123 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 8363b92..e05eedb 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -191,6 +191,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
> }
>
> /**
> + * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
> + * @hba: Pointer to adapter instance
> + *
> + * This function gets UIC command argument3
> + * Returns 0 on success, non zero value on error
> + */
> +static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
> +{
> + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
> +}
> +
> +/**
> * ufshcd_free_hba_memory - Free allocated memory for LRB, request
> * and task lists
> * @hba: Pointer to adapter instance
> @@ -1077,6 +1089,80 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
> }
>
> /**
> + * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
> + * @hba: per adapter instance
> + * @attr_sel: uic command argument1
> + * @attr_set: attribute set type as uic command argument2
> + * @mib_val: setting value as uic command argument3
> + * @peer: indicate wherter peer or non-peer
> + *
> + * Returns 0 on success, non-zero value on failure
> + */
> +int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val, u8 peer)
> +{
> + struct uic_command uic_cmd = {0};
> + static const char *const action[] = {
> + "dme-set",
> + "dme-peer-set"
> + };
> + const char *set = action[!!peer];
> + int ret;
> +
> + uic_cmd.command = peer ?
> + UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
> + uic_cmd.argument1 = attr_sel;
> + uic_cmd.argument2 = UIC_ARG_ATTR_SET(attr_set);
> + uic_cmd.argument3 = mib_val;
> +
> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> + if (ret)
> + dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
> + set, GET_UIC_ATTR_ID(attr_sel), ret);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
> +
> +/**
> + * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
> + * @hba: per adapter instance
> + * @attr_sel: uic command argument1
> + * @mib_val: the value of the attribute as returned by the UIC command
> + * @peer: indicate wherter peer or non-peer
> + *
> + * Returns 0 on success, non-zero value on failure
> + */
> +int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
> + u32 *mib_val, u8 peer)
> +{
> + struct uic_command uic_cmd = {0};
> + static const char *const action[] = {
> + "dme-get",
> + "dme-peer-get"
> + };
> + const char *get = action[!!peer];
> + int ret;
> +
> + uic_cmd.command = peer ?
> + UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
> + uic_cmd.argument1 = attr_sel;
> +
> + ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
> + if (ret) {
> + dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
> + get, GET_UIC_ATTR_ID(attr_sel), ret);
> + goto out;
> + }
> +
> + if (mib_val)
> + *mib_val = uic_cmd.argument3;
> +out:
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
> +
> +/**
> * ufshcd_make_hba_operational - Make UFS controller operational
> * @hba: per adapter instance
> *
> @@ -1538,6 +1624,8 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
> if (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);
> }
> }
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 974bd07..dabd29c 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -217,6 +217,11 @@ int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * ,
> unsigned int);
> void ufshcd_remove(struct ufs_hba *);
>
> +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);
> +
> /**
> * ufshcd_hba_stop - Send controller to reset state
> * @hba: per adapter instance
> @@ -226,4 +231,29 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba)
> ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE);
> }
>
> +/* UIC command interfaces for DME primitives */
> +static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val)
> +{
> + return ufshcd_dme_set_attr(hba, attr_sel, attr_set, mib_val, 0);
> +}
> +
> +static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
> + u8 attr_set, u32 mib_val)
> +{
> + return ufshcd_dme_set_attr(hba, attr_sel, attr_set, mib_val, 1);
> +}
> +
> +static inline int ufshcd_dme_get(struct ufs_hba *hba,
> + u32 attr_sel, u32 *mib_val)
> +{
> + return ufshcd_dme_get_attr(hba, attr_sel, mib_val, 0);
> +}
> +
> +static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
> + u32 attr_sel, u32 *mib_val)
> +{
> + return ufshcd_dme_get_attr(hba, attr_sel, mib_val, 1);
> +}
> +
> #endif /* End of Header */
> diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
> index f1e1b74..edb4d87 100644
> --- a/drivers/scsi/ufs/ufshci.h
> +++ b/drivers/scsi/ufs/ufshci.h
> @@ -191,6 +191,11 @@ enum {
> #define CONFIG_RESULT_CODE_MASK 0xFF
> #define GENERIC_ERROR_CODE_MASK 0xFF
>
> +#define UIC_ARG_MIB_SEL(attr, sel) ((((attr) & 0xFFFF) << 16) |\
> + ((sel) & 0xFFFF))
> +#define UIC_ARG_ATTR_SET(type) (((type) & 0xFF) << 16)
> +#define GET_UIC_ATTR_ID(val) (((val) >> 16) & 0xFFFF)
> +
> /* UIC Commands */
> enum {
> UIC_CMD_DME_GET = 0x01,
> --
> 1.7.0.4
>
>
Acked-by: Santosh Y <santoshsy@gmail.com>
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 6/6] scsi: ufs: add dme control primitives
2013-05-08 8:43 ` [PATCH v4 6/6] scsi: ufs: add dme control primitives Seungwon Jeon
@ 2013-05-09 6:53 ` Santosh Y
0 siblings, 0 replies; 52+ messages in thread
From: Santosh Y @ 2013-05-09 6:53 UTC (permalink / raw)
To: Seungwon Jeon; +Cc: linux-scsi, Vinayak Holikatti, James E.J. Bottomley
On Wed, May 8, 2013 at 2:13 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> 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
>
>
Acked-by: Santosh Y <santoshsy@gmail.com>
--
~Santosh
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-09 6:52 ` Santosh Y
@ 2013-05-09 14:21 ` James Bottomley
2013-05-10 1:52 ` Seungwon Jeon
0 siblings, 1 reply; 52+ messages in thread
From: James Bottomley @ 2013-05-09 14:21 UTC (permalink / raw)
To: Santosh Y; +Cc: Seungwon Jeon, linux-scsi, Vinayak Holikatti
On Thu, 2013-05-09 at 12:22 +0530, Santosh Y wrote:
> On Thu, May 9, 2013 at 12:09 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > On Thursday, May 09, 2013 Santosh wrote:
> >> > There are two patches remained. These are applied with your final comments.
> >> > Do you have any idea?
> >> > [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
> >> > [PATCH v4 6/6] scsi: ufs: add dme control primitives
> >> >
> >>
> >> Since there is no use case for these implementations yet, except for
> >> ufshcd_get_dme_attr_val(), as per James's suggestion
> >> [http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg20207.html]
> >> I did not ACK the patches.
> >> The same patches can be used to implement related features and resubmit later.
> > I respect your decision. But I have another opinion.
> > The remained patches are basic operations which should be supported by ufshcd.
> > Especially, dme_set/set will be used in vender specific part of host controller rather than in ufshcd itself.
> > And above all, Maya Erez completed to test and reported working fine.
> > If these patches are merged this time, it would be helpful to various hosts.
> >
>
> I'm ok with merging these patches if James is fine with it. I will ACK
> the patches.
Well, no, not really. The rule is simple: we don't add new functions to
the kernel without callers. The reason is also simple: trying to do
interface first and then user some time later is a "make work"
development strategy that practically guarantees the interface is either
never used or needs modification. From the kernel's point of view,
which is more important, review of a function with no callers is only
partial because you've no idea how it will be used. Whereas if you
review a function and its callers, you can see how the API works and
possibly suggest improvements.
James
^ permalink raw reply [flat|nested] 52+ messages in thread
* RE: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
2013-05-09 14:21 ` James Bottomley
@ 2013-05-10 1:52 ` Seungwon Jeon
0 siblings, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-10 1:52 UTC (permalink / raw)
To: 'James Bottomley', 'Santosh Y'
Cc: linux-scsi, 'Vinayak Holikatti'
On Thursday, May 09, 2013, James Bottomley wrote:
> On Thu, 2013-05-09 at 12:22 +0530, Santosh Y wrote:
> > On Thu, May 9, 2013 at 12:09 PM, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> > > On Thursday, May 09, 2013 Santosh wrote:
> > >> > There are two patches remained. These are applied with your final comments.
> > >> > Do you have any idea?
> > >> > [PATCH v4 5/6] scsi: ufs: add dme configuration primitives
> > >> > [PATCH v4 6/6] scsi: ufs: add dme control primitives
> > >> >
> > >>
> > >> Since there is no use case for these implementations yet, except for
> > >> ufshcd_get_dme_attr_val(), as per James's suggestion
> > >> [http://www.mail-archive.com/linux-scsi@vger.kernel.org/msg20207.html]
> > >> I did not ACK the patches.
> > >> The same patches can be used to implement related features and resubmit later.
> > > I respect your decision. But I have another opinion.
> > > The remained patches are basic operations which should be supported by ufshcd.
> > > Especially, dme_set/set will be used in vender specific part of host controller rather than in
> ufshcd itself.
> > > And above all, Maya Erez completed to test and reported working fine.
> > > If these patches are merged this time, it would be helpful to various hosts.
> > >
> >
> > I'm ok with merging these patches if James is fine with it. I will ACK
> > the patches.
>
> Well, no, not really. The rule is simple: we don't add new functions to
> the kernel without callers. The reason is also simple: trying to do
> interface first and then user some time later is a "make work"
> development strategy that practically guarantees the interface is either
> never used or needs modification. From the kernel's point of view,
> which is more important, review of a function with no callers is only
> partial because you've no idea how it will be used. Whereas if you
> review a function and its callers, you can see how the API works and
> possibly suggest improvements.
Thank you for your feedback.
Okay, it will be reintroduced with actual usage soon.
Could you pick the remains except [5/6, 6/6] into your tree?
The following patches include Santosh's ack.
[PATCH v4 1/6] scsi: ufs: wrap the i/o access operations
[PATCH v4 2/6] scsi: ufs: amend interrupt configuration
[PATCH v4 3/6] scsi: ufs: fix interrupt status clears
[PATCH v4 4/6] scsi: ufs: rework link start-up process
Thanks,
Seungwon Jeon
>
> James
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH] scsi: ufs: use devres functions for ufshcd
2013-05-04 8:45 ` [PATCH v2 1/7] " Seungwon Jeon
` (12 preceding siblings ...)
2013-05-08 8:43 ` [PATCH v4 6/6] scsi: ufs: add dme control primitives Seungwon Jeon
@ 2013-05-10 10:42 ` Seungwon Jeon
2013-05-10 11:00 ` Seungwon Jeon
2013-05-10 11:05 ` [PATCH resend] " Seungwon Jeon
13 siblings, 2 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-10 10:42 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
This patches replaces normal calls for resource allocation with devm_*()
derivative functions. It makes the routine to free resources simpler.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
drivers/scsi/ufs/ufshcd-pci.c | 1 -
drivers/scsi/ufs/ufshcd-pltfrm.c | 69 +++++++++----------------------------
drivers/scsi/ufs/ufshcd.c | 8 ++---
3 files changed, 20 insertions(+), 58 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 5cb1d75..48be39a 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -92,7 +92,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
struct ufs_hba *hba = pci_get_drvdata(pdev);
disable_irq(pdev->irq);
- free_irq(pdev->irq, hba);
ufshcd_remove(hba);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 03319ac..ad04eb4 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -33,9 +33,10 @@
* this program.
*/
-#include "ufshcd.h"
#include <linux/platform_device.h>
+#include "ufshcd.h"
+
#ifdef CONFIG_PM
/**
* ufshcd_pltfrm_suspend - suspend power management function
@@ -97,63 +98,43 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
struct ufs_hba *hba;
void __iomem *mmio_base;
struct resource *mem_res;
- struct resource *irq_res;
- resource_size_t mem_size;
- int err;
+ int irq, err;
struct device *dev = &pdev->dev;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
- dev_err(&pdev->dev,
- "Memory resource not available\n");
+ dev_err(dev, "Memory resource not available\n");
err = -ENODEV;
goto out_error;
}
- mem_size = resource_size(mem_res);
- if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) {
- dev_err(&pdev->dev,
- "Cannot reserve the memory resource\n");
- err = -EBUSY;
- goto out_error;
+ mmio_base = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(mmio_base)) {
+ dev_err(dev, "memory map failed\n");
+ return PTR_ERR(mmio_base);
}
- mmio_base = ioremap_nocache(mem_res->start, mem_size);
- if (!mmio_base) {
- dev_err(&pdev->dev, "memory map failed\n");
- err = -ENOMEM;
- goto out_release_regions;
- }
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res) {
- dev_err(&pdev->dev, "IRQ resource not available\n");
- err = -ENODEV;
- goto out_iounmap;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "IRQ resource not available\n");
+ return -ENODEV;
}
err = dma_set_coherent_mask(dev, dev->coherent_dma_mask);
if (err) {
- dev_err(&pdev->dev, "set dma mask failed\n");
- goto out_iounmap;
+ dev_err(dev, "set dma mask failed\n");
+ return err;
}
- err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
+ err = ufshcd_init(dev, &hba, mmio_base, irq);
if (err) {
- dev_err(&pdev->dev, "Intialization failed\n");
- goto out_iounmap;
+ dev_err(dev, "Intialization failed\n");
+ return err;
}
platform_set_drvdata(pdev, hba);
return 0;
-
-out_iounmap:
- iounmap(mmio_base);
-out_release_regions:
- release_mem_region(mem_res->start, mem_size);
-out_error:
- return err;
}
/**
@@ -164,26 +145,10 @@ out_error:
*/
static int ufshcd_pltfrm_remove(struct platform_device *pdev)
{
- struct resource *mem_res;
- resource_size_t mem_size;
struct ufs_hba *hba = platform_get_drvdata(pdev);
disable_irq(hba->irq);
-
- /* Some buggy controllers raise interrupt after
- * the resources are removed. So first we unregister the
- * irq handler and then the resources used by driver
- */
-
- free_irq(hba->irq, hba);
ufshcd_remove(hba);
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res)
- dev_err(&pdev->dev, "ufshcd: Memory resource not available\n");
- else {
- mem_size = resource_size(mem_res);
- release_mem_region(mem_res->start, mem_size);
- }
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8363b92..eb8a328 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2050,7 +2050,7 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
mutex_init(&hba->uic_cmd_mutex);
/* IRQ registration */
- err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+ err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
dev_err(hba->dev, "request irq failed\n");
goto out_lrb_free;
@@ -2060,13 +2060,13 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
err = scsi_init_shared_tag_map(host, host->can_queue);
if (err) {
dev_err(hba->dev, "init shared queue failed\n");
- goto out_free_irq;
+ goto out_lrb_free;
}
err = scsi_add_host(host, hba->dev);
if (err) {
dev_err(hba->dev, "scsi_add_host failed\n");
- goto out_free_irq;
+ goto out_lrb_free;
}
/* Host controller enable */
@@ -2084,8 +2084,6 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
out_remove_scsi_host:
scsi_remove_host(hba->host);
-out_free_irq:
- free_irq(irq, hba);
out_lrb_free:
ufshcd_free_hba_memory(hba);
out_disable:
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
* RE: [PATCH] scsi: ufs: use devres functions for ufshcd
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
1 sibling, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-10 11:00 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
Please ignore this one which is wrong sending.
Friday, May 10, 2013, Seungwon Jeon wrote:
> This patches replaces normal calls for resource allocation with devm_*()
> derivative functions. It makes the routine to free resources simpler.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> ---
> drivers/scsi/ufs/ufshcd-pci.c | 1 -
> drivers/scsi/ufs/ufshcd-pltfrm.c | 69 +++++++++----------------------------
> drivers/scsi/ufs/ufshcd.c | 8 ++---
> 3 files changed, 20 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
> index 5cb1d75..48be39a 100644
> --- a/drivers/scsi/ufs/ufshcd-pci.c
> +++ b/drivers/scsi/ufs/ufshcd-pci.c
> @@ -92,7 +92,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
> struct ufs_hba *hba = pci_get_drvdata(pdev);
>
> disable_irq(pdev->irq);
> - free_irq(pdev->irq, hba);
> ufshcd_remove(hba);
> pci_release_regions(pdev);
> pci_set_drvdata(pdev, NULL);
> diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
> index 03319ac..ad04eb4 100644
> --- a/drivers/scsi/ufs/ufshcd-pltfrm.c
> +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
> @@ -33,9 +33,10 @@
> * this program.
> */
>
> -#include "ufshcd.h"
> #include <linux/platform_device.h>
>
> +#include "ufshcd.h"
> +
> #ifdef CONFIG_PM
> /**
> * ufshcd_pltfrm_suspend - suspend power management function
> @@ -97,63 +98,43 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
> struct ufs_hba *hba;
> void __iomem *mmio_base;
> struct resource *mem_res;
> - struct resource *irq_res;
> - resource_size_t mem_size;
> - int err;
> + int irq, err;
> struct device *dev = &pdev->dev;
>
> mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (!mem_res) {
> - dev_err(&pdev->dev,
> - "Memory resource not available\n");
> + dev_err(dev, "Memory resource not available\n");
> err = -ENODEV;
> goto out_error;
> }
>
> - mem_size = resource_size(mem_res);
> - if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) {
> - dev_err(&pdev->dev,
> - "Cannot reserve the memory resource\n");
> - err = -EBUSY;
> - goto out_error;
> + mmio_base = devm_ioremap_resource(dev, mem_res);
> + if (IS_ERR(mmio_base)) {
> + dev_err(dev, "memory map failed\n");
> + return PTR_ERR(mmio_base);
> }
>
> - mmio_base = ioremap_nocache(mem_res->start, mem_size);
> - if (!mmio_base) {
> - dev_err(&pdev->dev, "memory map failed\n");
> - err = -ENOMEM;
> - goto out_release_regions;
> - }
> -
> - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> - if (!irq_res) {
> - dev_err(&pdev->dev, "IRQ resource not available\n");
> - err = -ENODEV;
> - goto out_iounmap;
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0) {
> + dev_err(dev, "IRQ resource not available\n");
> + return -ENODEV;
> }
>
> err = dma_set_coherent_mask(dev, dev->coherent_dma_mask);
> if (err) {
> - dev_err(&pdev->dev, "set dma mask failed\n");
> - goto out_iounmap;
> + dev_err(dev, "set dma mask failed\n");
> + return err;
> }
>
> - err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
> + err = ufshcd_init(dev, &hba, mmio_base, irq);
> if (err) {
> - dev_err(&pdev->dev, "Intialization failed\n");
> - goto out_iounmap;
> + dev_err(dev, "Intialization failed\n");
> + return err;
> }
>
> platform_set_drvdata(pdev, hba);
>
> return 0;
> -
> -out_iounmap:
> - iounmap(mmio_base);
> -out_release_regions:
> - release_mem_region(mem_res->start, mem_size);
> -out_error:
> - return err;
> }
>
> /**
> @@ -164,26 +145,10 @@ out_error:
> */
> static int ufshcd_pltfrm_remove(struct platform_device *pdev)
> {
> - struct resource *mem_res;
> - resource_size_t mem_size;
> struct ufs_hba *hba = platform_get_drvdata(pdev);
>
> disable_irq(hba->irq);
> -
> - /* Some buggy controllers raise interrupt after
> - * the resources are removed. So first we unregister the
> - * irq handler and then the resources used by driver
> - */
> -
> - free_irq(hba->irq, hba);
> ufshcd_remove(hba);
> - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!mem_res)
> - dev_err(&pdev->dev, "ufshcd: Memory resource not available\n");
> - else {
> - mem_size = resource_size(mem_res);
> - release_mem_region(mem_res->start, mem_size);
> - }
> platform_set_drvdata(pdev, NULL);
> return 0;
> }
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 8363b92..eb8a328 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -2050,7 +2050,7 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> mutex_init(&hba->uic_cmd_mutex);
>
> /* IRQ registration */
> - err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
> + err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
> if (err) {
> dev_err(hba->dev, "request irq failed\n");
> goto out_lrb_free;
> @@ -2060,13 +2060,13 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
> err = scsi_init_shared_tag_map(host, host->can_queue);
> if (err) {
> dev_err(hba->dev, "init shared queue failed\n");
> - goto out_free_irq;
> + goto out_lrb_free;
> }
>
> err = scsi_add_host(host, hba->dev);
> if (err) {
> dev_err(hba->dev, "scsi_add_host failed\n");
> - goto out_free_irq;
> + goto out_lrb_free;
> }
>
> /* Host controller enable */
> @@ -2084,8 +2084,6 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
>
> out_remove_scsi_host:
> scsi_remove_host(hba->host);
> -out_free_irq:
> - free_irq(irq, hba);
> out_lrb_free:
> ufshcd_free_hba_memory(hba);
> out_disable:
> --
> 1.7.0.4
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH resend] scsi: ufs: use devres functions for ufshcd
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 ` Seungwon Jeon
1 sibling, 0 replies; 52+ messages in thread
From: Seungwon Jeon @ 2013-05-10 11:05 UTC (permalink / raw)
To: linux-scsi
Cc: 'Vinayak Holikatti', 'Santosh Y',
'James E.J. Bottomley'
This patches replaces normal calls for resource allocation with devm_*()
derivative functions. It makes the routine to free resources simpler.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
---
drivers/scsi/ufs/ufshcd-pci.c | 1 -
drivers/scsi/ufs/ufshcd-pltfrm.c | 72 +++++++++----------------------------
drivers/scsi/ufs/ufshcd.c | 8 ++---
3 files changed, 21 insertions(+), 60 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 5cb1d75..48be39a 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -92,7 +92,6 @@ static void ufshcd_pci_remove(struct pci_dev *pdev)
struct ufs_hba *hba = pci_get_drvdata(pdev);
disable_irq(pdev->irq);
- free_irq(pdev->irq, hba);
ufshcd_remove(hba);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 03319ac..81d3db5 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -33,9 +33,10 @@
* this program.
*/
-#include "ufshcd.h"
#include <linux/platform_device.h>
+#include "ufshcd.h"
+
#ifdef CONFIG_PM
/**
* ufshcd_pltfrm_suspend - suspend power management function
@@ -97,63 +98,42 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
struct ufs_hba *hba;
void __iomem *mmio_base;
struct resource *mem_res;
- struct resource *irq_res;
- resource_size_t mem_size;
- int err;
+ int irq, err;
struct device *dev = &pdev->dev;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
- dev_err(&pdev->dev,
- "Memory resource not available\n");
- err = -ENODEV;
- goto out_error;
+ dev_err(dev, "Memory resource not available\n");
+ return -ENODEV;
}
- mem_size = resource_size(mem_res);
- if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) {
- dev_err(&pdev->dev,
- "Cannot reserve the memory resource\n");
- err = -EBUSY;
- goto out_error;
+ mmio_base = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(mmio_base)) {
+ dev_err(dev, "memory map failed\n");
+ return PTR_ERR(mmio_base);
}
- mmio_base = ioremap_nocache(mem_res->start, mem_size);
- if (!mmio_base) {
- dev_err(&pdev->dev, "memory map failed\n");
- err = -ENOMEM;
- goto out_release_regions;
- }
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res) {
- dev_err(&pdev->dev, "IRQ resource not available\n");
- err = -ENODEV;
- goto out_iounmap;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "IRQ resource not available\n");
+ return -ENODEV;
}
err = dma_set_coherent_mask(dev, dev->coherent_dma_mask);
if (err) {
- dev_err(&pdev->dev, "set dma mask failed\n");
- goto out_iounmap;
+ dev_err(dev, "set dma mask failed\n");
+ return err;
}
- err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start);
+ err = ufshcd_init(dev, &hba, mmio_base, irq);
if (err) {
- dev_err(&pdev->dev, "Intialization failed\n");
- goto out_iounmap;
+ dev_err(dev, "Intialization failed\n");
+ return err;
}
platform_set_drvdata(pdev, hba);
return 0;
-
-out_iounmap:
- iounmap(mmio_base);
-out_release_regions:
- release_mem_region(mem_res->start, mem_size);
-out_error:
- return err;
}
/**
@@ -164,26 +144,10 @@ out_error:
*/
static int ufshcd_pltfrm_remove(struct platform_device *pdev)
{
- struct resource *mem_res;
- resource_size_t mem_size;
struct ufs_hba *hba = platform_get_drvdata(pdev);
disable_irq(hba->irq);
-
- /* Some buggy controllers raise interrupt after
- * the resources are removed. So first we unregister the
- * irq handler and then the resources used by driver
- */
-
- free_irq(hba->irq, hba);
ufshcd_remove(hba);
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res)
- dev_err(&pdev->dev, "ufshcd: Memory resource not available\n");
- else {
- mem_size = resource_size(mem_res);
- release_mem_region(mem_res->start, mem_size);
- }
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 8363b92..eb8a328 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2050,7 +2050,7 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
mutex_init(&hba->uic_cmd_mutex);
/* IRQ registration */
- err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
+ err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
if (err) {
dev_err(hba->dev, "request irq failed\n");
goto out_lrb_free;
@@ -2060,13 +2060,13 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
err = scsi_init_shared_tag_map(host, host->can_queue);
if (err) {
dev_err(hba->dev, "init shared queue failed\n");
- goto out_free_irq;
+ goto out_lrb_free;
}
err = scsi_add_host(host, hba->dev);
if (err) {
dev_err(hba->dev, "scsi_add_host failed\n");
- goto out_free_irq;
+ goto out_lrb_free;
}
/* Host controller enable */
@@ -2084,8 +2084,6 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
out_remove_scsi_host:
scsi_remove_host(hba->host);
-out_free_irq:
- free_irq(irq, hba);
out_lrb_free:
ufshcd_free_hba_memory(hba);
out_disable:
--
1.7.0.4
^ permalink raw reply related [flat|nested] 52+ messages in thread
end of thread, other threads:[~2013-05-10 11:05 UTC | newest]
Thread overview: 52+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH v4 6/6] scsi: ufs: add dme control primitives Seungwon Jeon
2013-05-09 6:53 ` 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox