[PATCH v1 2/4] scsi: ufs: Implement Auto-Hibern8 setup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Michał Potomski <michalx.potomski@xxxxxxxxx>

Since Auto-Hibern8 feature has to be enabled by the user
proper API has been given via ioctl() by adding it to
already existing implementation of UFS ioctl().

We expose this API to user-space, since we don't know
in driver, what kind of additional Power Management rules
user wants to use. Due to that we want to expose API, to
let user or high level S/W decide, whether it wants to
use Auto-Hibern8 feature for Power Saving and give him
"slider" to decide between performance and power efficiency.
This is important because different platforms using
the same UFS host and/or device might want different
options on this one, e.g. High-End Desktop PC might
want to have this feature disabled, while Mobile or
Server platforms might want to have this feature enabled,
but levels will vary depending on what's to be achieved.

As this feature is meant to be transparent for driver,
we'd like to let user decide whether he wants this enabled
or not.

Signed-off-by: Michał Potomski <michalx.potomski@xxxxxxxxx>
---
 Documentation/scsi/ufs.txt      | 47 +++++++++++++++++++++++++++++++
 drivers/scsi/ufs/ufshcd-ioctl.c | 62 +++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/ufs/ufshcd.c       | 25 +++++++++++++++++
 drivers/scsi/ufs/ufshcd.h       |  4 +++
 drivers/scsi/ufs/ufshci.h       |  9 ++++--
 include/scsi/scsi.h             |  2 +-
 include/uapi/scsi/ufs/Kbuild    |  1 +
 include/uapi/scsi/ufs/ioctl.h   | 31 +++++++++++++++++++++
 include/uapi/scsi/ufs/ufshci.h  | 17 +++++++++++
 9 files changed, 194 insertions(+), 4 deletions(-)
 create mode 100644 include/uapi/scsi/ufs/ufshci.h

diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
index 7326974..6c0e995 100644
--- a/Documentation/scsi/ufs.txt
+++ b/Documentation/scsi/ufs.txt
@@ -17,6 +17,7 @@ Contents
   3.4 SCSI Error handling
 4. UFSHCD User Interface
   4.1 UFS Query IOCTL
+  4.2 UFS Auto-Hibern8 IOCTL
 
 
 1. Overview
@@ -174,6 +175,52 @@ host and device using IOCTL interface.
   This enables user to control some of the UFS specific features inaccessible
   in other way.
 
+4.2 UFS Auto-Hibern8 IOCTL
+
+  This interface enables user to get/set information about UFS Host
+  Auto-Hibern8 feature for capable hosts. You can use following snippet
+  to comunicate with this interface:
+
+	#include <sys/ioctl.h>
+	#include <scsi/ufs/ioctl.h>
+	#include <scsi/ufs/ufshci.h>
+
+	static int handleWrite(int fd, uint8_t scale, uint16_t timer_val)
+	{
+		ufs_ioctl_auto_hibern8_data hibern8_data;
+
+		/* State, that we want to write the data */
+		hibern8_data.write = true;
+
+		/* Timer scale (check <scsi/ufs/ufshci.h>) */
+		hibern8_data.scale = *scale;
+
+		/* Timer value (max. 0x3fff) */
+		hibern8_data.timer_val = *timer_val;
+
+		/* [fd] used here shall be opened UFS device */
+		return ioctl(fd, UFS_IOCTL_AUTO_HIBERN8, &hibern8_data);
+	}
+
+	static int handleRead(int fd, uint8_t *scale, uint16_t *timer_val)
+	{
+		ufs_ioctl_auto_hibern8_data hibern8_data;
+		int error;
+
+		/* State, that we want to read data  */
+		hibern8_data.write = false;
+
+		/* [fd] used here shall be opened UFS device */
+		error = ioctl(fd, UFS_IOCTL_AUTO_HIBERN8, &hibern8_data);
+
+		if (!error) {
+			*scale = hibern8_data.scale;
+			*timer_val = hibern8_data.timer_val;
+		}
+
+		return error;
+	}
+
 
 UFS Specifications can be found at,
 UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
diff --git a/drivers/scsi/ufs/ufshcd-ioctl.c b/drivers/scsi/ufs/ufshcd-ioctl.c
index ae70bf5..71f4026 100644
--- a/drivers/scsi/ufs/ufshcd-ioctl.c
+++ b/drivers/scsi/ufs/ufshcd-ioctl.c
@@ -273,6 +273,62 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
 	return err;
 }
 
+static int ufshcd_auto_hibern8_ioctl(struct ufs_hba *hba, void __user *buffer)
+{
+	struct ufs_ioctl_auto_hibern8_data *ioctl_data;
+	int err = 0;
+	u32 status = 0;
+
+	if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+		return -ENOTSUPP;
+
+	if (!buffer)
+		return -EINVAL;
+
+	ioctl_data = kzalloc(sizeof(struct ufs_ioctl_auto_hibern8_data),
+				GFP_KERNEL);
+	if (!ioctl_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* extract params from user buffer */
+	if (copy_from_user(ioctl_data, buffer, sizeof(*ioctl_data))) {
+		err = -EFAULT;
+		goto out_release_mem;
+	}
+
+	if (ioctl_data->write) {
+		if (ioctl_data->timer_val > UFSHCD_AHIBERN8_TIMER_MASK ||
+		    (ioctl_data->scale >= UFSHCD_AHIBERN8_SCALE_MAX)) {
+			err = -EINVAL;
+			goto out_release_mem;
+		}
+
+		/* Write valid state to host */
+		ufshcd_setup_auto_hibern8(hba, ioctl_data->scale,
+			ioctl_data->timer_val);
+	} else {
+		status = ufshcd_read_auto_hibern8_state(hba);
+		ioctl_data->scale =
+			(status & UFSHCD_AHIBERN8_SCALE_MASK) >> 10;
+		ioctl_data->timer_val =
+			(status & UFSHCD_AHIBERN8_TIMER_MASK);
+
+		/* Copy state to user */
+		err = copy_to_user(buffer, ioctl_data, sizeof(*ioctl_data));
+	}
+
+out_release_mem:
+	kfree(ioctl_data);
+out:
+	if (err)
+		dev_err(hba->dev, "Auto-Hibern8 request failed (error: %d)",
+			err);
+
+	return err;
+}
+
 /**
  * ufshcd_ioctl - ufs ioctl callback registered in scsi_host
  * @dev: scsi device required for per LUN queries
@@ -281,6 +337,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
  *
  * Supported commands:
  * UFS_IOCTL_QUERY
+ * UFS_IOCTL_AUTO_HIBERN8
  */
 int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
 {
@@ -297,6 +354,11 @@ int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
 				buffer);
 		pm_runtime_put_sync(hba->dev);
 		break;
+	case UFS_IOCTL_AUTO_HIBERN8:
+		pm_runtime_get_sync(hba->dev);
+		err = ufshcd_auto_hibern8_ioctl(hba, buffer);
+		pm_runtime_put_sync(hba->dev);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		break;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9f3a39d..6fcbeb5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -933,6 +933,30 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
 }
 
 /**
+ * ufshcd_read_auto_hibern8_state - Reads hosts auto-hibern8 feature state
+ * @hba: per adapter instance
+ */
+u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba)
+{
+	return ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
+}
+
+/**
+ * ufshcd_setup_auto_hibern8 - Sets up hosts auto-hibern8 feature
+ * @hba: per adapter instance
+ * @scale: timer scale (1/10/100us/1/10/100ms)
+ * @timer_val: value to be multipled with scale (idle timeout)
+ */
+void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val)
+{
+	u32 val = (scale << 10) & UFSHCD_AHIBERN8_SCALE_MASK;
+
+	val |= timer_val & UFSHCD_AHIBERN8_TIMER_MASK;
+
+	ufshcd_writel(hba, val, REG_AUTO_HIBERNATE_IDLE_TIMER);
+}
+
+/**
  * ufshcd_is_devfreq_scaling_required - check if scaling is required or not
  * @hba: per adapter instance
  * @scale_up: True if scaling up and false if scaling down
@@ -5338,6 +5362,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
 static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
 {
 	hba->errors = UFSHCD_ERROR_MASK & intr_status;
+
 	if (hba->errors)
 		ufshcd_check_errors(hba);
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bf8a670..392f702 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -860,6 +860,10 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
 u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun);
 u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id);
 
+/* Expose Auto-Hibern8 API */
+void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val);
+u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba);
+
 /* Wrapper functions for safely calling variant operations */
 static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
 {
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f60145d..789bbd8 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -36,6 +36,8 @@
 #ifndef _UFSHCI_H
 #define _UFSHCI_H
 
+#include <scsi/ufs/ufshci.h>
+
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
@@ -86,6 +88,7 @@ enum {
 enum {
 	MASK_TRANSFER_REQUESTS_SLOTS		= 0x0000001F,
 	MASK_TASK_MANAGEMENT_REQUEST_SLOTS	= 0x00070000,
+	MASK_AUTO_HIBERN8_SUPPORT		= 0x00800000,
 	MASK_64_ADDRESSING_SUPPORT		= 0x01000000,
 	MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT	= 0x02000000,
 	MASK_UIC_DME_TEST_MODE_SUPPORT		= 0x04000000,
@@ -136,9 +139,9 @@ enum {
 #define CONTROLLER_FATAL_ERROR			UFS_BIT(16)
 #define SYSTEM_BUS_FATAL_ERROR			UFS_BIT(17)
 
-#define UFSHCD_UIC_PWR_MASK	(UIC_HIBERNATE_ENTER |\
-				UIC_HIBERNATE_EXIT |\
-				UIC_POWER_MODE)
+#define UFSHCD_UHS_MASK		(UIC_HIBERNATE_EXIT | UIC_HIBERNATE_ENTER)
+
+#define UFSHCD_UIC_PWR_MASK	(UFSHCD_UHS_MASK | UIC_POWER_MODE)
 
 #define UFSHCD_UIC_MASK		(UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
 
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index f128e9e..43f87ad 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -255,7 +255,7 @@ static inline int scsi_is_wlun(u64 lun)
  * Here are some scsi specific ioctl commands which are sometimes useful.
  *
  * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
- * include/uapi/scsi/ufs/ioctl.h defines 0x53A0
+ * include/uapi/scsi/ufs/ioctl.h defines 0x53A0 - 0x53A1
  */
 
 /* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
diff --git a/include/uapi/scsi/ufs/Kbuild b/include/uapi/scsi/ufs/Kbuild
index cc3ef20..07a2ce3 100644
--- a/include/uapi/scsi/ufs/Kbuild
+++ b/include/uapi/scsi/ufs/Kbuild
@@ -1,3 +1,4 @@
 # UAPI Header export list
 header-y += ioctl.h
 header-y += ufs.h
+header-y += ufshci.h
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
index 1c65505..f3583de 100644
--- a/include/uapi/scsi/ufs/ioctl.h
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -8,6 +8,7 @@
  *  SCSI_IOCTL_GET_PCI
  */
 #define UFS_IOCTL_QUERY			0x53A0
+#define UFS_IOCTL_AUTO_HIBERN8		0x53A1
 
 /**
  * struct ufs_ioctl_query_data - used to transfer data to and from user via
@@ -58,4 +59,34 @@ struct ufs_ioctl_query_data {
 	__u8 *buffer;
 };
 
+/**
+ * struct ufs_ioctl_auto_hibern8_data - used to hold Auto-Hibern8 feature
+ * configuration
+ *
+ * @write: flag indicating whether config should be written or read
+ * @scale: scale of the timer (length of one tick)
+ * @timer_val: value of the timer to be multipled by scale (0x0000-0x3FFF)
+ *
+ * Received/Submitted: scale, timer_val
+ */
+struct ufs_ioctl_auto_hibern8_data {
+	/*
+	 * This flag indicates whether configuration wirtten in this structure
+	 * should be written, or overwritten by reading currently written
+	 */
+	bool write;
+
+	/*
+	 * Scale of the timer. Prease refer to <uapi/scsi/ufs/ufshci.h> for
+	 * correct values and their meaning.
+	 */
+	__u8 scale;
+
+	/*
+	 * Actual timer value, which will be multipled by the scale.
+	 * Maximal value: 1023. 0 will disable the feature.
+	 */
+	__u16 timer_val;
+};
+
 #endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufshci.h b/include/uapi/scsi/ufs/ufshci.h
new file mode 100644
index 0000000..c50065b
--- /dev/null
+++ b/include/uapi/scsi/ufs/ufshci.h
@@ -0,0 +1,17 @@
+#ifndef _UAPI_UFSHCI_H
+#define _UAPI_UFSHCI_H
+
+enum {
+	UFSHCD_AHIBERN8_SCALE_1US	= 0,
+	UFSHCD_AHIBERN8_SCALE_10US	= 1,
+	UFSHCD_AHIBERN8_SCALE_100US	= 2,
+	UFSHCD_AHIBERN8_SCALE_1MS	= 3,
+	UFSHCD_AHIBERN8_SCALE_10MS	= 4,
+	UFSHCD_AHIBERN8_SCALE_100MS	= 5,
+	UFSHCD_AHIBERN8_SCALE_MAX,
+};
+
+#define UFSHCD_AHIBERN8_TIMER_MASK		0x03ff
+#define UFSHCD_AHIBERN8_SCALE_MASK		0x1C00
+
+#endif
-- 
1.9.1

--------------------------------------------------------------------

Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux