Skip to contentSkip to conversation

scsi: ufs: Add support for sending NOP OUT UPIU

PATCH Superseded Sujit Reddy Thumma 6 participants 52 messages Apr 24, 2013 – May 10, 2013

Subsystems (2)

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 scsi: ufs: Add support for sending NOP OUT UPIU

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.

---
 drivers/scsi/ufs/ufshcd.c |  167 ++++++++++++++++++++++++++++++++++++++++++---
 drivers/scsi/ufs/ufshcd.h |    4 +
 2 files changed, 162 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +158 -9
index ced421a..1a8cba3 100644
@@ -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;
drivers/scsi/ufs/ufshcd.h +4 -0
index 13378f3..e273bf7 100644
@@ -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;
 };
 
 /**
Signature · 2 lines
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation.
#1 lore raw

PATCH 1/5 scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index 60fd40c..41b9639 100644
@@ -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
  *
drivers/scsi/ufs/ufshcd.h +0 -9
index 6b99a42..1680394 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#2 lore raw

Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

Looks good. Reviewed-by: Subhash Jadavani <[email protected]>

Quoted 46 lines · Seungwon Jeon

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index 60fd40c..41b9639 100644
@@ -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
  *
drivers/scsi/ufs/ufshcd.h +0 -9
index 6b99a42..1680394 100644
@@ -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 */
#3 lore raw

Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

Quoted 58 lines

Looks good. Reviewed-by: Subhash Jadavani <[email protected]>

Quoted 47 lines · Seungwon Jeon

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index 60fd40c..41b9639 100644
@@ -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

*

drivers/scsi/ufs/ufshcd.h +0 -9
index 6b99a42..1680394 100644
@@ -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));
-}
-
Quoted 1 line

#endif /* End of Header */

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#4 lore raw

Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

In reply to Seungwon Jeon
Quoted 47 lines · Seungwon Jeon

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index 60fd40c..41b9639 100644
@@ -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
  *
drivers/scsi/ufs/ufshcd.h +0 -10
index 6b99a42..1680394 100644
@@ -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 */
--
Quoted 3 lines

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"

Signature · 1 line
~Santosh
#5 lore raw

RE: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

Quoted 54 lines · Santosh Y
Quoted 47 lines · Seungwon Jeon

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index 60fd40c..41b9639 100644
@@ -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
  *
drivers/scsi/ufs/ufshcd.h +0 -10
index 6b99a42..1680394 100644
@@ -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 */
--
Quoted 3 lines

1.7.0.4

The patch doesn't apply due to the character set.

Quoted 1 line

"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

Quoted 8 lines

--
~Santosh
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#6 lore raw

Re: [PATCH 1/5] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

In reply to Santosh Y

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

Quoted 69 lines
Quoted 51 lines · Seungwon Jeon

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index 60fd40c..41b9639 100644
@@ -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
*

drivers/scsi/ufs/ufshcd.h +0 -7
index 6b99a42..1680394 100644
@@ -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));

drivers/scsi/ufs/ufshcd.h +0 -3
-}
-
 #endif /* End of Header */
--
Quoted 3 lines

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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#7 lore raw

PATCH v2 1/7 scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

In reply to Seungwon Jeon

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index f244812..d932239 100644
@@ -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
  *
drivers/scsi/ufs/ufshcd.h +0 -9
index 336980b..3a1052d 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#8 lore raw

Re: [PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

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

Quoted 59 lines

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index f244812..d932239 100644
@@ -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

*

drivers/scsi/ufs/ufshcd.h +0 -9
index 336980b..3a1052d 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#9 lore raw

RE: [PATCH v2 1/7] scsi: ufs: move the ufshcd_hba_stop to ufshcd.c

Quoted 7 lines · Merze

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

Quoted 73 lines

Thanks,
Maya

Quoted 54 lines

Move the ufshcd_hba_stop from header file.

---
 drivers/scsi/ufs/ufshcd.c |    9 +++++++++
 drivers/scsi/ufs/ufshcd.h |    9 ---------
 2 files changed, 9 insertions(+), 9 deletions(-)
drivers/scsi/ufs/ufshcd.c +9 -0
index f244812..d932239 100644
@@ -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

*

drivers/scsi/ufs/ufshcd.h +0 -9
index 336980b..3a1052d 100644
@@ -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

Quoted 5 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw

PATCH v3 1/6 scsi: ufs: wrap the i/o access operations

In reply to Seungwon Jeon

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105 +++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +44 -61
index f244812..cf7c8e4 100644
@@ -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);
 
drivers/scsi/ufs/ufshcd.h +6 -1
index 336980b..6429bed 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#11 lore raw

Re: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations

Hi James,

Can you please merge this patch on top of the query requests patch?

Thanks,
Maya

Quoted 313 lines

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105
+++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +2 -3
index f244812..cf7c8e4 100644
@@ -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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +8 -11
@@ -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;
 	}

}

drivers/scsi/ufs/ufshcd.c +4 -6
@@ -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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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;
 }
 

/**

drivers/scsi/ufs/ufshcd.c +2 -4
@@ -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 */
drivers/scsi/ufs/ufshcd.c +5 -8
 	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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +5 -6
@@ -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;
 	}

}

drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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,
drivers/scsi/ufs/ufshcd.c +1 -1
 			"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");
drivers/scsi/ufs/ufshcd.c +8 -8
 		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 */
drivers/scsi/ufs/ufshcd.c +1 -2
 	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;
 
drivers/scsi/ufs/ufshcd.c +4 -7
 	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;
 	}
drivers/scsi/ufs/ufshcd.c +1 -2
 	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);
 
drivers/scsi/ufs/ufshcd.h +6 -2
index 336980b..6429bed 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#12 lore raw

Re: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations

In reply to Seungwon Jeon
Quoted 291 lines · Seungwon Jeon

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105 +++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +44 -61
index f244812..cf7c8e4 100644
@@ -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);
 
drivers/scsi/ufs/ufshcd.h +6 -2
index 336980b..6429bed 100644
@@ -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 */
--
Quoted 2 lines

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.

Signature · 1 line
~Santosh
#13 lore raw

RE: [PATCH v3 1/6] scsi: ufs: wrap the i/o access operations

Quoted 290 lines · Santosh Y
Quoted 289 lines · Seungwon Jeon

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105 +++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +44 -61
index f244812..cf7c8e4 100644
@@ -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);
 
drivers/scsi/ufs/ufshcd.h +6 -1
index 336980b..6429bed 100644
@@ -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);
 }
 
Quoted 7 lines
Quoted 4 lines
drivers/scsi/ufs/ufshcd.h +0 -1
 #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

Quoted 7 lines

--
~Santosh
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#14 lore raw

PATCH v3 2/6 scsi: ufs: amend interrupt configuration

In reply to Seungwon Jeon

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.

---
 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(-)
drivers/scsi/ufs/ufshcd.c +59 -25
index cf7c8e4..feaf221 100644
@@ -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) {
drivers/scsi/ufs/ufshcd.h +2 -2
index 6429bed..d98e046 100644
@@ -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;
drivers/scsi/ufs/ufshci.h +3 -2
index 4a86247..f1e1b74 100644
@@ -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,
 };
 
 /*
Signature · 1 line
1.7.0.4
#15 lore raw

Re: [PATCH v3 2/6] scsi: ufs: amend interrupt configuration

Hi James,

Can you please merge this patch?

Thanks,
Maya

Quoted 206 lines

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.

---
 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(-)
drivers/scsi/ufs/ufshcd.c +54 -17
index cf7c8e4..feaf221 100644
@@ -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 */
drivers/scsi/ufs/ufshcd.c +1 -7
 	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 */
drivers/scsi/ufs/ufshcd.c +4 -1
 	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);
drivers/scsi/ufs/ufshcd.c +0 -0
 	if (err) {
drivers/scsi/ufs/ufshcd.h +2 -2
index 6429bed..d98e046 100644
@@ -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;
drivers/scsi/ufs/ufshci.h +3 -3
index 4a86247..f1e1b74 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#16 lore raw

PATCH v3 3/6 scsi: ufs: fix interrupt status clears

In reply to Seungwon Jeon

There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.

---
 drivers/scsi/ufs/ufshcd.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)
drivers/scsi/ufs/ufshcd.c +1 -4
index feaf221..e04c74e 100644
@@ -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);
Signature · 1 line
1.7.0.4
Tested-by on v3 3/6
#17 lore raw

Re: [PATCH v3 3/6] scsi: ufs: fix interrupt status clears

Quoted 36 lines

There is no need to check the version to clear
the interrupt status. And the order is changed
prior to actual handling.

---
 drivers/scsi/ufs/ufshcd.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)
drivers/scsi/ufs/ufshcd.c +1 -4
index feaf221..e04c74e 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#18 lore raw

PATCH v3 4/6 scsi: ufs: rework link start-up process

In reply to Seungwon Jeon

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.

---
 drivers/scsi/ufs/ufshcd.c |  287 ++++++++++++++++++++++++++++++---------------
 drivers/scsi/ufs/ufshcd.h |   10 +-
 2 files changed, 200 insertions(+), 97 deletions(-)
drivers/scsi/ufs/ufshcd.c +193 -94
index e04c74e..118f104 100644
@@ -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:
drivers/scsi/ufs/ufshcd.h +7 -3
index d98e046..974bd07 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#19 lore raw

Re: [PATCH v3 4/6] scsi: ufs: rework link start-up process

Quoted 7 lines · Seungwon Jeon

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.

drivers/scsi/ufs/ufshcd.c +1 -0
index ecbae40..ae22a8e 100644
@@ -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 =

Quoted 503 lines

Added mutex to guarantee of uic command at a time. Adapted some sequence of controller initialization after link statup according to HCI standard.

---
  drivers/scsi/ufs/ufshcd.c |  287 ++++++++++++++++++++++++++++++---------------
  drivers/scsi/ufs/ufshcd.h |   10 +-
  2 files changed, 200 insertions(+), 97 deletions(-)
drivers/scsi/ufs/ufshcd.c +193 -94
index e04c74e..118f104 100644
@@ -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:
drivers/scsi/ufs/ufshcd.h +7 -3
index d98e046..974bd07 100644
@@ -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 */
Signature · 2 lines
Regards,
Sujit
#20 lore raw

Re: [PATCH v3 4/6] scsi: ufs: rework link start-up process

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

Quoted 614 lines · Seungwon Jeon
Quoted 7 lines

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.

drivers/scsi/ufs/ufshcd.c +6 -1
index ecbae40..ae22a8e 100644
@@ -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 =

Quoted 514 lines

Added mutex to guarantee of uic command at a time. Adapted some sequence of controller initialization after link statup according to HCI standard.

---
  drivers/scsi/ufs/ufshcd.c |  287
++++++++++++++++++++++++++++++---------------
  drivers/scsi/ufs/ufshcd.h |   10 +-
  2 files changed, 200 insertions(+), 97 deletions(-)
drivers/scsi/ufs/ufshcd.c +38 -7
index e04c74e..118f104 100644
@@ -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)

drivers/scsi/ufs/ufshcd.c +72 -26
+{
+	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;
  }
 

/**

drivers/scsi/ufs/ufshcd.c +4 -3
@@ -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
   */
drivers/scsi/ufs/ufshcd.c +16 -0
@@ -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

drivers/scsi/ufs/ufshcd.c +1 -7
@@ -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;
  }
drivers/scsi/ufs/ufshcd.c +1 -3
@@ -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
*/

drivers/scsi/ufs/ufshcd.c +35 -16
-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
*/

drivers/scsi/ufs/ufshcd.c +0 -22
@@ -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
   */
drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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);
drivers/scsi/ufs/ufshcd.c +18 -1
@@ -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) {
drivers/scsi/ufs/ufshcd.c +6 -3
@@ -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:

drivers/scsi/ufs/ufshcd.h +7 -2
index d98e046..974bd07 100644
@@ -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;
 

drivers/scsi/ufs/ufshcd.h struct ufs_hba { · line 204

Quoted 7 lines
drivers/scsi/ufs/ufshcd.h +0 -1
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#21 lore raw

RE: [PATCH v3 4/6] scsi: ufs: rework link start-up process

In reply to Sujit Reddy Thumma
Quoted 42 lines · Sujit Reddy Thumma
Quoted 7 lines · Seungwon Jeon

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
Quoted 5 lines

[<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

Quoted 548 lines
drivers/scsi/ufs/ufshcd.c +6 -1
index ecbae40..ae22a8e 100644
@@ -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 =

Quoted 496 lines

Added mutex to guarantee of uic command at a time. Adapted some sequence of controller initialization after link statup according to HCI standard.

---
  drivers/scsi/ufs/ufshcd.c |  287 ++++++++++++++++++++++++++++++---------------
  drivers/scsi/ufs/ufshcd.h |   10 +-
  2 files changed, 200 insertions(+), 97 deletions(-)
drivers/scsi/ufs/ufshcd.c +193 -94
index e04c74e..118f104 100644
@@ -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:
drivers/scsi/ufs/ufshcd.h +7 -2
index d98e046..974bd07 100644
@@ -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;
 

drivers/scsi/ufs/ufshcd.h struct ufs_hba { · line 204

Quoted 7 lines
drivers/scsi/ufs/ufshcd.h +0 -1
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#22 lore raw

RE: [PATCH v3 4/6] scsi: ufs: rework link start-up process

Quoted 60 lines · Sujit Reddy Thumma
Quoted 42 lines · Seungwon Jeon
Quoted 7 lines

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
Quoted 5 lines

[<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.

Quoted 2 lines

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

Quoted 576 lines
Quoted 560 lines
drivers/scsi/ufs/ufshcd.c +1 -0
index ecbae40..ae22a8e 100644
@@ -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,
drivers/scsi/ufs/ufshcd.c +5 -1
 					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 =

Quoted 8 lines

Added mutex to guarantee of uic command at a time. Adapted some sequence of controller initialization after link statup according to HCI standard.

---
  drivers/scsi/ufs/ufshcd.c |  287

++++++++++++++++++++++++++++++---------------

drivers/scsi/ufs/ufshcd.c static inline void

Quoted 24 lines
  drivers/scsi/ufs/ufshcd.h |   10 +-
  2 files changed, 200 insertions(+), 97 deletions(-)
drivers/scsi/ufs/ufshcd.c +4 -0
index e04c74e..118f104 100644
@@ -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)

Quoted 17 lines
drivers/scsi/ufs/ufshcd.c +11 -2
  }
 
  /**
- * 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;
+}

drivers/scsi/ufs/ufshcd.c static inline void · line 409

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +7 -1
+
+/**
+ * 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)

drivers/scsi/ufs/ufshcd.c static inline void · line 429

Quoted 1 line
drivers/scsi/ufs/ufshcd.c +1 -0
+ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command

*uic_cmd)

Quoted 17 lines
drivers/scsi/ufs/ufshcd.c +6 -4
  {
+	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);
  }
 

drivers/scsi/ufs/ufshcd.c static inline void · line 452

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +9 -0
  /**
+ * 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)

Quoted 13 lines
drivers/scsi/ufs/ufshcd.c +13 -0
+{
+	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;
+}
+
+/**

drivers/scsi/ufs/ufshcd.c static inline void · line 475

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +10 -0
+ * __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)

drivers/scsi/ufs/ufshcd.c static void ufshcd_host_memory_configure(struct

Quoted 45 lines
drivers/scsi/ufs/ufshcd.c +41 -0
+{
+	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)

drivers/scsi/ufs/ufshcd.c static int ufshcd_dme_link_startup(struct

Quoted 43 lines
drivers/scsi/ufs/ufshcd.c +8 -26
   */
  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)

drivers/scsi/ufs/ufshcd.c static int ufshcd_make_hba_operational(struct

Quoted 14 lines
drivers/scsi/ufs/ufshcd.c +4 -3
   *
   * 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)

drivers/scsi/ufs/ufshcd.c static int ufshcd_make_hba_operational(struct

Quoted 23 lines
drivers/scsi/ufs/ufshcd.c +16 -0
  		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)

drivers/scsi/ufs/ufshcd.c static int ufshcd_hba_enable(struct ufs_hba

Quoted 19 lines
drivers/scsi/ufs/ufshcd.c +1 -7
  		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)

drivers/scsi/ufs/ufshcd.c static int ufshcd_hba_enable(struct ufs_hba · line 1116

Quoted 9 lines
drivers/scsi/ufs/ufshcd.c +1 -3
  }
 
  /**
- * 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

drivers/scsi/ufs/ufshcd.c static int ufshcd_hba_enable(struct ufs_hba · line 1118

Quoted 2 lines
drivers/scsi/ufs/ufshcd.c +0 -2
- * UTRDL.
- * 3. Program the Task Management Request List Address with starting

address

drivers/scsi/ufs/ufshcd.c static int ufshcd_do_reset(struct ufs_hba

Quoted 41 lines
drivers/scsi/ufs/ufshcd.c +16 -17
- * 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)

drivers/scsi/ufs/ufshcd.c ufshcd_transfer_rsp_status(struct ufs_hba *hba,

Quoted 22 lines
drivers/scsi/ufs/ufshcd.c +9 -2
  	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)

Quoted 5 lines
drivers/scsi/ufs/ufshcd.c +2 -0
  }
 
  /**
+ * ufshcd_uic_cmd_compl - handle completion of uic command
+ * @hba: per adapter instance

drivers/scsi/ufs/ufshcd.c ufshcd_transfer_rsp_status(struct ufs_hba *hba, · line 1538

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +9 -0
+ */
+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

drivers/scsi/ufs/ufshcd.c static void ufshcd_transfer_req_compl(struct

Quoted 3 lines
drivers/scsi/ufs/ufshcd.c +0 -0
   * @hba: per adapter instance
   */
@@ -1473,28 +1574,6 @@ static void ufshcd_transfer_req_compl(struct

ufs_hba *hba)

drivers/scsi/ufs/ufshcd.c static void ufshcd_sl_intr(struct ufs_hba *hba,

Quoted 29 lines
drivers/scsi/ufs/ufshcd.c +0 -22
  }
 
  /**
- * 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)

drivers/scsi/ufs/ufshcd.c int ufshcd_init(struct device *dev, struct

Quoted 31 lines
drivers/scsi/ufs/ufshcd.c +16 -1
  		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,

drivers/scsi/ufs/ufshcd.c int ufshcd_init(struct device *dev, struct

Quoted 16 lines
drivers/scsi/ufs/ufshcd.c +3 -1
  	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,

Quoted 79 lines
drivers/scsi/ufs/ufshcd.c +6 -3
  		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:
drivers/scsi/ufs/ufshcd.h +7 -3
index d98e046..974bd07 100644
@@ -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;
 
Quoted 10 lines

drivers/scsi/ufs/ufshcd.h struct ufs_hba { · line 204

Quoted 2 lines
drivers/scsi/ufs/ufshcd.h +0 -0
  	/* HBA Errors */

--
Regards,
Sujit
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#23 lore raw

PATCH v3 5/6 scsi: ufs: add dme configuration primitives

In reply to Seungwon Jeon

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.

---
 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
drivers/scsi/ufs/ufshcd.c +84 -0
index 118f104..aa06210 100644
@@ -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);
 }
 
drivers/scsi/ufs/ufshcd.h +30 -0
index 974bd07..93965b9 100644
@@ -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 */
drivers/scsi/ufs/ufshci.h +4 -0
index f1e1b74..c7d6a1b 100644
@@ -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,
drivers/scsi/ufs/unipro.h new file +130 -0

130 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#24 lore raw

Re: [PATCH v3 5/6] scsi: ufs: add dme configuration primitives

Quoted 119 lines

/**
+ * 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
+ */

drivers/scsi/ufs/ufshcd.c +63 -0
+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);
 }
 
drivers/scsi/ufs/ufshcd.h +20 -0
index 974bd07..93965b9 100644
@@ -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)

drivers/scsi/ufs/ufshcd.h static inline void ufshcd_hba_stop(struct ufs_hba *hba) · line 258

Quoted 10 lines
drivers/scsi/ufs/ufshcd.h +10 -0
+{
+       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().

Signature · 1 line
~Santosh
#25 lore raw

PATCH v3 6/6 scsi: ufs: add dme control primitives

In reply to Seungwon Jeon

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.

---
 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(-)
drivers/scsi/ufs/ufshcd.c +124 -8
index aa06210..3607ffb 100644
@@ -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);
drivers/scsi/ufs/ufshcd.h +26 -0
index 93965b9..84f758e 100644
@@ -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 */
drivers/scsi/ufs/ufshci.h +15 -0
index c7d6a1b..d60703f 100644
@@ -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
Signature · 1 line
1.7.0.4
#26 lore raw

Re: [PATCH v3 6/6] scsi: ufs: add dme control primitives

Quoted 66 lines

/**
+ * 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
+ */

drivers/scsi/ufs/ufshcd.c +59 -0
+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;
+               }

drivers/scsi/ufs/ufshcd.c int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel, · line 1242

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +10 -0
+       } 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.

Signature · 1 line
~Santosh
#27 lore raw

RE: [PATCH v3 6/6] scsi: ufs: add dme control primitives

Quoted 73 lines · Santosh Y
Quoted 73 lines

/**
+ * 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
+ */

drivers/scsi/ufs/ufshcd.c +66 -0
+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;
Quoted 8 lines

drivers/scsi/ufs/ufshcd.c int ufshcd_dme_xxx_get(struct ufs_hba *hba, u32 attr_sel, · line 1242

Quoted 3 lines
drivers/scsi/ufs/ufshcd.c +3 -0
+}
+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

Quoted 8 lines

--
~Santosh
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#28 lore raw

PATCH v4 1/6 scsi: ufs: wrap the i/o access operations

In reply to Seungwon Jeon

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105 +++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +44 -61
index f244812..cf7c8e4 100644
@@ -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);
 
drivers/scsi/ufs/ufshcd.h +6 -1
index 336980b..6429bed 100644
@@ -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 */
Signature · 1 line
1.7.0.4
#29 lore raw

Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Hi,

I tested the new set of patches (v4 1-6) and it works.

Thanks,
Maya

Quoted 313 lines

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105
+++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +2 -3
index f244812..cf7c8e4 100644
@@ -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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +8 -11
@@ -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;
 	}

}

drivers/scsi/ufs/ufshcd.c +4 -6
@@ -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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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;
 }
 

/**

drivers/scsi/ufs/ufshcd.c +2 -4
@@ -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 */
drivers/scsi/ufs/ufshcd.c +5 -8
 	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);
 }
 

/**

drivers/scsi/ufs/ufshcd.c +5 -6
@@ -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;
 	}

}

drivers/scsi/ufs/ufshcd.c +1 -1
@@ -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,
drivers/scsi/ufs/ufshcd.c +1 -1
 			"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");
drivers/scsi/ufs/ufshcd.c +8 -8
 		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 */
drivers/scsi/ufs/ufshcd.c +1 -2
 	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;
 
drivers/scsi/ufs/ufshcd.c +4 -7
 	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;
 	}
drivers/scsi/ufs/ufshcd.c +1 -2
 	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);
 
drivers/scsi/ufs/ufshcd.h +6 -2
index 336980b..6429bed 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 3 lines
Maya Erez
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
#30 lore raw

Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

In reply to Seungwon Jeon
Quoted 291 lines · Seungwon Jeon

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105 +++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
drivers/scsi/ufs/ufshcd.c +44 -61
index f244812..cf7c8e4 100644
@@ -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);
 
drivers/scsi/ufs/ufshcd.h +6 -2
index 336980b..6429bed 100644
@@ -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 */
--
Quoted 2 lines

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 <[email protected]>, if you are able to apply the patches.

Signature · 1 line
~Santosh
#31 lore raw

RE: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Quoted 10 lines · Santosh Y
Quoted 9 lines · Seungwon Jeon

Simplify operations with hiding mmio_base.

---
 drivers/scsi/ufs/ufshcd.c |  105 +++++++++++++++++++--------------------------
 drivers/scsi/ufs/ufshcd.h |    7 +++-
 2 files changed, 50 insertions(+), 62 deletions(-)
Quoted 6 lines

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.

Quoted 5 lines

Hi James,
Please consider Acked-by: Santosh Y <[email protected]>, 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

#32 lore raw

Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Quoted 5 lines

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/[email protected]/msg20207.html]
I did not ACK the patches.
The same patches can be used to implement related features and resubmit later.

Signature · 1 line
~Santosh
#33 lore raw

RE: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Quoted 11 lines · On Thursday, May 09, 2013 Santosh wrote:
Quoted 5 lines

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/[email protected]/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

Quoted 7 lines

--
~Santosh
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#34 lore raw

Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Quoted 12 lines · Seungwon Jeon
Quoted 11 lines · On Thursday, May 09, 2013 Santosh wrote:
Quoted 5 lines

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/[email protected]/msg20207.html]
I did not ACK the patches.
The same patches can be used to implement related features and resubmit later.

Quoted 6 lines

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.

Signature · 1 line
~Santosh
maintainer
#35 lore raw

Re: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Quoted 20 lines · Santosh Y
Quoted 12 lines · Seungwon Jeon
Quoted 11 lines · On Thursday, May 09, 2013 Santosh wrote:
Quoted 5 lines

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/[email protected]/msg20207.html]
I did not ACK the patches.
The same patches can be used to implement related features and resubmit later.

Quoted 6 lines

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.

Quoted 2 lines

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

#36 lore raw

RE: [PATCH v4 1/6] scsi: ufs: wrap the i/o access operations

Quoted 25 lines · James Bottomley
Quoted 8 lines · Santosh Y
Quoted 7 lines · Seungwon Jeon
Quoted 6 lines · On Thursday, May 09, 2013 Santosh wrote:
Quoted 5 lines

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

Quoted 8 lines
Quoted 8 lines
Quoted 5 lines

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/[email protected]/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.

Quoted 6 lines
Quoted 3 lines

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.

Quoted 9 lines

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

Quoted 9 lines

James

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#37 lore raw

PATCH v4 2/6 scsi: ufs: amend interrupt configuration

In reply to Seungwon Jeon

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.

---
 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(-)
drivers/scsi/ufs/ufshcd.c +59 -25
index cf7c8e4..feaf221 100644
@@ -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) {
drivers/scsi/ufs/ufshcd.h +2 -2
index 6429bed..d98e046 100644
@@ -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;
drivers/scsi/ufs/ufshci.h +3 -2
index 4a86247..f1e1b74 100644
@@ -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,
 };
 
 /*
Signature · 1 line
1.7.0.4
Acked-by on v4 2/6
#38 lore raw

Re: [PATCH v4 2/6] scsi: ufs: amend interrupt configuration

Quoted 194 lines · Seungwon Jeon

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.

---
 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(-)
drivers/scsi/ufs/ufshcd.c +59 -25
index cf7c8e4..feaf221 100644
@@ -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) {
drivers/scsi/ufs/ufshcd.h +2 -2
index 6429bed..d98e046 100644
@@ -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;
drivers/scsi/ufs/ufshci.h +3 -3
index 4a86247..f1e1b74 100644
@@ -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,
 };
 
 /*
--
Quoted 3 lines

1.7.0.4

Signature · 1 line
~Santosh
#39 lore raw

PATCH v4 3/6 scsi: ufs: fix interrupt status clears

In reply to Seungwon Jeon

There is no need to check the version to clear the interrupt status. And the order is changed prior to actual handling.

---
 drivers/scsi/ufs/ufshcd.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)
drivers/scsi/ufs/ufshcd.c +1 -4
index feaf221..e04c74e 100644
@@ -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);
Signature · 1 line
1.7.0.4
Acked-by on v4 3/6
#40 lore raw

Re: [PATCH v4 3/6] scsi: ufs: fix interrupt status clears

Quoted 28 lines · Seungwon Jeon

There is no need to check the version to clear the interrupt status. And the order is changed prior to actual handling.

---
 drivers/scsi/ufs/ufshcd.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)
drivers/scsi/ufs/ufshcd.c +1 -5
index feaf221..e04c74e 100644
@@ -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);
--
Quoted 3 lines

1.7.0.4

Signature · 1 line
~Santosh
#41 lore raw

PATCH v4 4/6 scsi: ufs: rework link start-up process

In reply to Seungwon Jeon

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.

---
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(-)
drivers/scsi/ufs/ufshcd.c +201 -94
index e04c74e..8363b92 100644
@@ -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:
drivers/scsi/ufs/ufshcd.h +7 -3
index d98e046..974bd07 100644
@@ -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 */
Signature · 1 line
1.7.0.4
Acked-by on v4 4/6
#42 lore raw

Re: [PATCH v4 4/6] scsi: ufs: rework link start-up process

Quoted 523 lines · Seungwon Jeon

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.

---
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(-)
drivers/scsi/ufs/ufshcd.c +201 -94
index e04c74e..8363b92 100644
@@ -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:
drivers/scsi/ufs/ufshcd.h +7 -4
index d98e046..974bd07 100644
@@ -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 */
--
Quoted 3 lines

1.7.0.4

Signature · 1 line
~Santosh
#43 lore raw

PATCH v4 5/6 scsi: ufs: add dme configuration primitives

In reply to Seungwon Jeon

Implements to support Get and Set operation of the DME. These operations are used to configure the behavior of the UNIPRO.

---
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(-)
drivers/scsi/ufs/ufshcd.c +88 -0
index 8363b92..e05eedb 100644
@@ -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);
 	}
 }
drivers/scsi/ufs/ufshcd.h +30 -0
index 974bd07..dabd29c 100644
@@ -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 */
drivers/scsi/ufs/ufshci.h +5 -0
index f1e1b74..edb4d87 100644
@@ -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,
Signature · 1 line
1.7.0.4
Acked-by on v4 5/6
#44 lore raw

Re: [PATCH v4 5/6] scsi: ufs: add dme configuration primitives

Quoted 192 lines · Seungwon Jeon

Implements to support Get and Set operation of the DME. These operations are used to configure the behavior of the UNIPRO.

---
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(-)
drivers/scsi/ufs/ufshcd.c +88 -0
index 8363b92..e05eedb 100644
@@ -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);
        }
 }
drivers/scsi/ufs/ufshcd.h +30 -0
index 974bd07..dabd29c 100644
@@ -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 */
drivers/scsi/ufs/ufshci.h +5 -1
index f1e1b74..edb4d87 100644
@@ -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,
--
Quoted 3 lines

1.7.0.4

Signature · 1 line
~Santosh
#45 lore raw

PATCH v4 6/6 scsi: ufs: add dme control primitives

In reply to Seungwon Jeon

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.

---
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(-)
drivers/scsi/ufs/ufshcd.c +119 -4
index e05eedb..45123b4 100644
@@ -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);
drivers/scsi/ufs/ufshcd.h +26 -0
index dabd29c..0465885 100644
@@ -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 */
drivers/scsi/ufs/ufshci.h +15 -0
index edb4d87..8ddecaa 100644
@@ -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
Signature · 1 line
1.7.0.4
Acked-by on v4 6/6
#46 lore raw

Re: [PATCH v4 6/6] scsi: ufs: add dme control primitives

Quoted 277 lines · Seungwon Jeon

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.

---
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(-)
drivers/scsi/ufs/ufshcd.c +119 -4
index e05eedb..45123b4 100644
@@ -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);
drivers/scsi/ufs/ufshcd.h +26 -0
index dabd29c..0465885 100644
@@ -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 */
drivers/scsi/ufs/ufshci.h +15 -1
index edb4d87..8ddecaa 100644
@@ -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
--
Quoted 3 lines

1.7.0.4

Signature · 1 line
~Santosh
#47 lore raw

PATCH 1/1 scsi: ufs: use devres functions for ufshcd

In reply to Seungwon Jeon

This patches replaces normal calls for resource allocation with devm_*() derivative functions. It makes the routine to free resources simpler.

---
 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(-)
drivers/scsi/ufs/ufshcd-pci.c +0 -1
index 5cb1d75..48be39a 100644
@@ -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);
drivers/scsi/ufs/ufshcd-pltfrm.c +17 -52

115 lines not on this page · raw message

drivers/scsi/ufs/ufshcd.c +3 -5
index 8363b92..eb8a328 100644
@@ -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:
Signature · 1 line
1.7.0.4
#48 lore raw

RE: [PATCH] scsi: ufs: use devres functions for ufshcd

Please ignore this one which is wrong sending.

Quoted 190 lines · Seungwon Jeon

This patches replaces normal calls for resource allocation with devm_*() derivative functions. It makes the routine to free resources simpler.

---
 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(-)
drivers/scsi/ufs/ufshcd-pci.c +0 -1
index 5cb1d75..48be39a 100644
@@ -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);
drivers/scsi/ufs/ufshcd-pltfrm.c +17 -52
index 03319ac..ad04eb4 100644
@@ -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;
 }
drivers/scsi/ufs/ufshcd.c +3 -6
index 8363b92..eb8a328 100644
@@ -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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#49 lore raw

PATCH RESEND 1/1 scsi: ufs: use devres functions for ufshcd

In reply to Seungwon Jeon

This patches replaces normal calls for resource allocation with devm_*() derivative functions. It makes the routine to free resources simpler.

---
 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(-)
drivers/scsi/ufs/ufshcd-pci.c +0 -1
index 5cb1d75..48be39a 100644
@@ -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);
drivers/scsi/ufs/ufshcd-pltfrm.c +18 -54

116 lines not on this page · raw message

drivers/scsi/ufs/ufshcd.c +3 -5
index 8363b92..eb8a328 100644
@@ -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:
Signature · 1 line
1.7.0.4
#50 lore raw
In reply to Sujit Reddy Thumma
Quoted 53 lines
drivers/scsi/ufs/ufshcd.c +53 -0
+
+/**
+ * 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;

drivers/scsi/ufs/ufshcd.c static int ufshcd_dme_link_startup(struct ufs_hba *hba) · line 1216

Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +10 -0
+
+               /* 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)).

Quoted 5 lines
drivers/scsi/ufs/ufshcd.c +5 -0
+                       retries = 0;
+               spin_lock_irqsave(hba->host->host_lock, flags);
+               goto may_retry;
+       }
+
Signature · 1 line
~Santosh
#51 lore raw
Quoted 57 lines · Santosh Y
Quoted 57 lines
drivers/scsi/ufs/ufshcd.c +57 -0
+
+/**
+ * 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);
Quoted 8 lines

drivers/scsi/ufs/ufshcd.c static int ufshcd_dme_link_startup(struct ufs_hba *hba) · line 1216

Quoted 6 lines
drivers/scsi/ufs/ufshcd.c +6 -0
+
+               /* 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.

Quoted 9 lines
Quoted 6 lines
drivers/scsi/ufs/ufshcd.c +5 -0
+                       retries = 0;
+               spin_lock_irqsave(hba->host->host_lock, flags);
+               goto may_retry;
+       }
+
Signature · 2 lines
Regards,
Sujit