diff mbox

[v2] scsi: ufs: Implement Auto-Hibern8 setup

Message ID 20170725094514.19192-1-michalx.potomski@intel.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Potomski, MichalX July 25, 2017, 9:45 a.m. UTC
From: Michał Potomski <michalx.potomski@intel.com>

Since Auto-Hibern8 feature has to be enabled by the user
proper API has been given via SysFS.

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

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@intel.com>
---
 drivers/scsi/ufs/ufshcd.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/ufs/ufshcd.h |  2 ++
 drivers/scsi/ufs/ufshci.h | 23 +++++++++---
 3 files changed, 112 insertions(+), 4 deletions(-)

Comments

Bart Van Assche July 25, 2017, 3:30 p.m. UTC | #1
On Tue, 2017-07-25 at 11:45 +0200, Michal Potomski wrote:
> Since Auto-Hibern8 feature has to be enabled by the user
> proper API has been given via SysFS.
> 
> 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 acheived.
> 
> As this feature is meant to be transparent for driver,
> we'd like to let user decide whether he wants this enabled
> or not.

Less than ten minutes after v1 of this patch was posted version v2 was
posted. What is the difference between v1 and v2? Second and later versions
of a patch or patch series are expected to include a changelog.

Since I'm not familiar with the Auto-Hibern8 feature: what impact does it
have on command processing? Does it e.g. cause SCSI or TMF commands that are
sent to the UFS device to be ignored, to fail or to time out?

> +static ssize_t ufshcd_auto_hibern8_show(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct ufs_hba *hba = dev_get_drvdata(dev);
> +	u32 val;
> +	unsigned long timer;
> +	u8 scale;
> +	char *unit;
> +
> +	val = ufshcd_read_auto_hibern8_state(hba);
> +	timer = val & UFSHCI_AHIBERN8_TIMER_MASK;
> +	scale =	(val & UFSHCI_AHIBERN8_SCALE_MASK)
> +			>> UFSHCI_AHIBERN8_SCALE_OFFSET;
> +
> +	unit = scale >= UFSHCI_AHIBERN8_SCALE_1MS ? "ms" : "us";
> +
> +	for (scale %= UFSHCI_AHIBERN8_SCALE_1MS; scale > 0; --scale)
> +		timer *= UFS_AHIBERN8_SCALE_STEP_MAGNITUDE;
> +
> +	return snprintf(buf, PAGE_SIZE, "%ld %s\n", timer, unit);
> +}

From Documentation/filesystems/sysfs.txt: "All new sysfs attributes must be
documented in Documentation/ABI. See also Documentation/ABI/README for more
information." Please add proper documentation of the attributes added by this
patch when you resubmit this patch.

Regarding this attribute: units should be documented in Documentation/ABI/*/*
instead of specifying these in the attribute itself. In other words, the
"ms" / "us" suffix should be left out.

> @@ -7693,16 +7766,34 @@ static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
>  		dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
>  }
>  
> +static void ufshcd_add_ahibern8_sysfs_node(struct ufs_hba *hba)
> +{
> +	if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
> +		return;
> +
> +	hba->ahibern8_attr.show = ufshcd_auto_hibern8_show;
> +	hba->ahibern8_attr.store = ufshcd_auto_hibern8_store;
> +	sysfs_attr_init(&hba->ahibern8_attr.attr);
> +	hba->ahibern8_attr.attr.name = "ufs_auto_hibern8";
> +	hba->ahibern8_attr.attr.mode = 0600;
> +	if (device_create_file(hba->dev, &hba->ahibern8_attr))
> +		dev_err(hba->dev, "Failed to create sysfs for ufs_auto_hibern8\n");
> +}

Please use a static variable at file scope and DRIVER_ATTR_RW() to initialize
the sysfs attributes instead of initializing the sysfs attributes explicitly.

Additionally, please set sdev_attrs in struct scsi_host_template instead of
calling device_create_file() explicitly. The above device_create_file() call
occurs after a UFS device has been made visible in sysfs and hence will cause
trouble (race condition) if a udev rule tries to set this attribute from inside
a rule that is triggered by device creation.

I am aware the above code follows the style that is used for other UFS sysfs
attributes. If you would have the time to convert the code for creating the
existing UFS sysfs attributes that would be great.

Thanks,

Bart.
Potomski, MichalX July 25, 2017, 4:54 p.m. UTC | #2
> On Tue, 2017-07-25 at 11:45 +0200, Michal Potomski wrote:
> > Since Auto-Hibern8 feature has to be enabled by the user
> > proper API has been given via SysFS.
> >
> > 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 acheived.
> >
> > As this feature is meant to be transparent for driver,
> > we'd like to let user decide whether he wants this enabled
> > or not.
> 
> Less than ten minutes after v1 of this patch was posted version v2 was
> posted. What is the difference between v1 and v2? Second and later versions
> of a patch or patch series are expected to include a changelog.
> 
V1 had some minor style issues, which were present in version that wasn't
targeted to be sent, hence the quick V2 post, which was the corrected one.

Proper changelog will be included in future versions.
> Since I'm not familiar with the Auto-Hibern8 feature: what impact does it
> have on command processing? Does it e.g. cause SCSI or TMF commands that
> are
> sent to the UFS device to be ignored, to fail or to time out?
> 
Actually behavior should be transparent for all of the higher layers, since this
shall be fully controlled by UFS Host, which will put UFS Device to Hibern8 state,
when it has no ongoing commands to it for set up time. If there will be any command
UFS Host should order the Device to exit Hibern8 mode and proceed normally.

Bottom line is that in model case, it shouldn't cause any of errors mentioned by you.
There is possible throughput degradation in case, if transfers are sporadic in terms
of timer, which we did set up, though. According to specification it also shouldn't affect
Hibern8 states triggered by Power Management, nor any other functionality.

I will alter commit message in V3, to cover this question.
> > +static ssize_t ufshcd_auto_hibern8_show(struct device *dev,
> > +		struct device_attribute *attr, char *buf)
> > +{
> > +	struct ufs_hba *hba = dev_get_drvdata(dev);
> > +	u32 val;
> > +	unsigned long timer;
> > +	u8 scale;
> > +	char *unit;
> > +
> > +	val = ufshcd_read_auto_hibern8_state(hba);
> > +	timer = val & UFSHCI_AHIBERN8_TIMER_MASK;
> > +	scale =	(val & UFSHCI_AHIBERN8_SCALE_MASK)
> > +			>> UFSHCI_AHIBERN8_SCALE_OFFSET;
> > +
> > +	unit = scale >= UFSHCI_AHIBERN8_SCALE_1MS ? "ms" : "us";
> > +
> > +	for (scale %= UFSHCI_AHIBERN8_SCALE_1MS; scale > 0; --scale)
> > +		timer *= UFS_AHIBERN8_SCALE_STEP_MAGNITUDE;
> > +
> > +	return snprintf(buf, PAGE_SIZE, "%ld %s\n", timer, unit);
> > +}
> 
> From Documentation/filesystems/sysfs.txt: "All new sysfs attributes must be
> documented in Documentation/ABI. See also Documentation/ABI/README for
> more
> information." Please add proper documentation of the attributes added by this
> patch when you resubmit this patch.
> 
> Regarding this attribute: units should be documented in Documentation/ABI/*/*
> instead of specifying these in the attribute itself. In other words, the
> "ms" / "us" suffix should be left out.
> 
Will be fixed in V3
> > @@ -7693,16 +7766,34 @@ static void
> ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
> >  		dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
> >  }
> >
> > +static void ufshcd_add_ahibern8_sysfs_node(struct ufs_hba *hba)
> > +{
> > +	if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
> > +		return;
> > +
> > +	hba->ahibern8_attr.show = ufshcd_auto_hibern8_show;
> > +	hba->ahibern8_attr.store = ufshcd_auto_hibern8_store;
> > +	sysfs_attr_init(&hba->ahibern8_attr.attr);
> > +	hba->ahibern8_attr.attr.name = "ufs_auto_hibern8";
> > +	hba->ahibern8_attr.attr.mode = 0600;
> > +	if (device_create_file(hba->dev, &hba->ahibern8_attr))
> > +		dev_err(hba->dev, "Failed to create sysfs for
> ufs_auto_hibern8\n");
> > +}
> 
> Please use a static variable at file scope and DRIVER_ATTR_RW() to initialize
> the sysfs attributes instead of initializing the sysfs attributes explicitly.
> 
> Additionally, please set sdev_attrs in struct scsi_host_template instead of
> calling device_create_file() explicitly. The above device_create_file() call
> occurs after a UFS device has been made visible in sysfs and hence will cause
> trouble (race condition) if a udev rule tries to set this attribute from inside
> a rule that is triggered by device creation.
> 
> I am aware the above code follows the style that is used for other UFS sysfs
> attributes. If you would have the time to convert the code for creating the
> existing UFS sysfs attributes that would be great.
> 
Will be added to V3 and sent as patch set.
> Thanks,
> 
> Bart.
Cheers,
Michal
--------------------------------------------------------------------

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.
Bart Van Assche July 26, 2017, 3:25 p.m. UTC | #3
On Tue, 2017-07-25 at 16:54 +0000, Potomski, MichalX wrote:
> On Tue, 2017-07-25 at 15:30 +0000, Bart Van Assche wrote:
> > Since I'm not familiar with the Auto-Hibern8 feature: what impact does it
> > have on command processing? Does it e.g. cause SCSI or TMF commands that
> > are
> > sent to the UFS device to be ignored, to fail or to time out?
> 
> Actually behavior should be transparent for all of the higher layers, since this
> shall be fully controlled by UFS Host, which will put UFS Device to Hibern8 state,
> when it has no ongoing commands to it for set up time. If there will be any command
> UFS Host should order the Device to exit Hibern8 mode and proceed normally.
> 
> Bottom line is that in model case, it shouldn't cause any of errors mentioned by you.
> There is possible throughput degradation in case, if transfers are sporadic in terms
> of timer, which we did set up, though. According to specification it also shouldn't affect
> Hibern8 states triggered by Power Management, nor any other functionality.

Hello Michal,

SCSI requests can not only be initiated by user space but also by the kernel
itself. Are SCSI UFS devices controlled by the SCSI disk (sd) driver? Will
SCSI requests submitted by sd_check_events() to a hibernated UFS device time
out and activate the SCSI error handler?

Thanks,

Bart.
Potomski, MichalX July 27, 2017, 9:15 a.m. UTC | #4
> On Tue, 2017-07-25 at 16:54 +0000, Potomski, MichalX wrote:
> > On Tue, 2017-07-25 at 15:30 +0000, Bart Van Assche wrote:
> > > Since I'm not familiar with the Auto-Hibern8 feature: what impact
> > > does it have on command processing? Does it e.g. cause SCSI or TMF
> > > commands that are sent to the UFS device to be ignored, to fail or
> > > to time out?
> >
> > Actually behavior should be transparent for all of the higher layers,
> > since this shall be fully controlled by UFS Host, which will put UFS
> > Device to Hibern8 state, when it has no ongoing commands to it for set
> > up time. If there will be any command UFS Host should order the Device to exit
> Hibern8 mode and proceed normally.
> >
> > Bottom line is that in model case, it shouldn't cause any of errors mentioned
> by you.
> > There is possible throughput degradation in case, if transfers are
> > sporadic in terms of timer, which we did set up, though. According to
> > specification it also shouldn't affect
> > Hibern8 states triggered by Power Management, nor any other functionality.
> 
> Hello Michal,
> 
> SCSI requests can not only be initiated by user space but also by the kernel itself.
> Are SCSI UFS devices controlled by the SCSI disk (sd) driver? Will SCSI requests
> submitted by sd_check_events() to a hibernated UFS device time out and
> activate the SCSI error handler?

Hello Bart,

Technically according to JESD220B UFS 2.0 spec, available on jedec.com website,
this feature should work autonomously. It means, that when Device will be
put in Hibern8 state by the host in Auto-Hibern8 procedure, actions other than
reading DME Hibern8 status will cause Host to pull the Device out of Hibern8 state
and proceed normally. Since all requests to the Device go through Host, then
in theory it shouldn't interfere with any request made by anyone. Obviously it
fully depends on the UFS Host and how it implements this feature. It all bases on
trust, that if anyone flagged such capability in Host, did his job well and implemented
feature correctly.

Just to answer your questions in short manner:
 - Yes, it is controlled by SCSI disk driver.
 - No, if implemented correctly in Host it shouldn't time out any requests. For other
   cases we can have quirks, to disable such feature for Hosts that do not support this
   correctly (despite of being flagged with capability to do so).
> 
> Thanks,
> 
> Bart.
Cheers,
Michal
--------------------------------------------------------------------

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.
Bart Van Assche July 27, 2017, 3:07 p.m. UTC | #5
Hello Michal,

Please configure your e-mail client such that it inserts a "On $(date) $(author)
wrote:" line in replies. As one can see below that line is missing from your
replies.

On Thu, 2017-07-27 at 09:15 +0000, Potomski, MichalX wrote:
> > On Tue, 2017-07-25 at 16:54 +0000, Potomski, MichalX wrote:
> > > On Tue, 2017-07-25 at 15:30 +0000, Bart Van Assche wrote:
> > > > Since I'm not familiar with the Auto-Hibern8 feature: what impact
> > > > does it have on command processing? Does it e.g. cause SCSI or TMF
> > > > commands that are sent to the UFS device to be ignored, to fail or
> > > > to time out?
> > > 
> > > Actually behavior should be transparent for all of the higher layers,
> > > since this shall be fully controlled by UFS Host, which will put UFS
> > > Device to Hibern8 state, when it has no ongoing commands to it for set
> > > up time. If there will be any command UFS Host should order the Device to exit
> > 
> > Hibern8 mode and proceed normally.
> > > 
> > > Bottom line is that in model case, it shouldn't cause any of errors mentioned
> > 
> > by you.
> > > There is possible throughput degradation in case, if transfers are
> > > sporadic in terms of timer, which we did set up, though. According to
> > > specification it also shouldn't affect
> > > Hibern8 states triggered by Power Management, nor any other functionality.
> > 
> > Hello Michal,
> > 
> > SCSI requests can not only be initiated by user space but also by the kernel itself.
> > Are SCSI UFS devices controlled by the SCSI disk (sd) driver? Will SCSI requests
> > submitted by sd_check_events() to a hibernated UFS device time out and
> > activate the SCSI error handler?
> 
> Hello Bart,
> 
> Technically according to JESD220B UFS 2.0 spec, available on jedec.com website,
> this feature should work autonomously. It means, that when Device will be
> put in Hibern8 state by the host in Auto-Hibern8 procedure, actions other than
> reading DME Hibern8 status will cause Host to pull the Device out of Hibern8 state
> and proceed normally. Since all requests to the Device go through Host, then
> in theory it shouldn't interfere with any request made by anyone. Obviously it
> fully depends on the UFS Host and how it implements this feature. It all bases on
> trust, that if anyone flagged such capability in Host, did his job well and implemented
> feature correctly.
> 
> Just to answer your questions in short manner:
>  - Yes, it is controlled by SCSI disk driver.
>  - No, if implemented correctly in Host it shouldn't time out any requests. For other
>    cases we can have quirks, to disable such feature for Hosts that do not support this
>    correctly (despite of being flagged with capability to do so).

If the polling that is performed by the sd driver is not stopped when a UFS
device is hibernated then that polling (sd_check_events()) will wake up a UFS
drive from the hibernated state. Shouldn't sd/sr polling be suspended while a
UFS device is in the hibernated state?

Thanks,

Bart.
diff mbox

Patch

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5bc9dc14e075..7bed33a023db 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -931,6 +931,31 @@  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_HIBERN8_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 << UFSHCI_AHIBERN8_SCALE_OFFSET)
+			& UFSHCI_AHIBERN8_SCALE_MASK;
+
+	val |= timer_val & UFSHCI_AHIBERN8_TIMER_MASK;
+
+	ufshcd_writel(hba, val, REG_AUTO_HIBERN8_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
@@ -5715,6 +5740,54 @@  static int ufshcd_abort(struct scsi_cmnd *cmd)
 	return err;
 }
 
+#define UFS_AHIBERN8_SCALE_STEP_MAGNITUDE	10
+
+static ssize_t ufshcd_auto_hibern8_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+	u32 val;
+	unsigned long timer;
+	u8 scale;
+	char *unit;
+
+	val = ufshcd_read_auto_hibern8_state(hba);
+	timer = val & UFSHCI_AHIBERN8_TIMER_MASK;
+	scale =	(val & UFSHCI_AHIBERN8_SCALE_MASK)
+			>> UFSHCI_AHIBERN8_SCALE_OFFSET;
+
+	unit = scale >= UFSHCI_AHIBERN8_SCALE_1MS ? "ms" : "us";
+
+	for (scale %= UFSHCI_AHIBERN8_SCALE_1MS; scale > 0; --scale)
+		timer *= UFS_AHIBERN8_SCALE_STEP_MAGNITUDE;
+
+	return snprintf(buf, PAGE_SIZE, "%ld %s\n", timer, unit);
+}
+
+static ssize_t ufshcd_auto_hibern8_store(struct device *dev,
+		struct device_attribute *atr, const char *buf, size_t count)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+	unsigned long timer;
+	u8 scale = UFSHCI_AHIBERN8_SCALE_1US;
+
+	if (kstrtoul(buf, 0, &timer))
+		return -EINVAL;
+
+	while (timer > UFSHCI_AHIBERN8_TIMER_MASK &&
+	       scale < UFSHCI_AHIBERN8_SCALE_MAX) {
+		timer /= UFS_AHIBERN8_SCALE_STEP_MAGNITUDE;
+		++scale;
+	}
+
+	if (scale >= UFSHCI_AHIBERN8_SCALE_MAX)
+		return -EINVAL;
+
+	ufshcd_setup_auto_hibern8(hba, scale, (u16) timer);
+
+	return count;
+}
+
 /**
  * ufshcd_host_reset_and_restore - reset and restore host controller
  * @hba: per-adapter instance
@@ -7693,16 +7766,34 @@  static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
 		dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
 }
 
+static void ufshcd_add_ahibern8_sysfs_node(struct ufs_hba *hba)
+{
+	if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+		return;
+
+	hba->ahibern8_attr.show = ufshcd_auto_hibern8_show;
+	hba->ahibern8_attr.store = ufshcd_auto_hibern8_store;
+	sysfs_attr_init(&hba->ahibern8_attr.attr);
+	hba->ahibern8_attr.attr.name = "ufs_auto_hibern8";
+	hba->ahibern8_attr.attr.mode = 0600;
+	if (device_create_file(hba->dev, &hba->ahibern8_attr))
+		dev_err(hba->dev, "Failed to create sysfs for ufs_auto_hibern8\n");
+}
+
 static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
 {
 	ufshcd_add_rpm_lvl_sysfs_nodes(hba);
 	ufshcd_add_spm_lvl_sysfs_nodes(hba);
+	ufshcd_add_ahibern8_sysfs_node(hba);
 }
 
 static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba)
 {
 	device_remove_file(hba->dev, &hba->rpm_lvl_attr);
 	device_remove_file(hba->dev, &hba->spm_lvl_attr);
+
+	if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)
+		device_remove_file(hba->dev, &hba->ahibern8_attr);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index cdc8bd05f7df..5ae470bad75e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -677,6 +677,8 @@  struct ufs_hba {
 
 	struct rw_semaphore clk_scaling_lock;
 	struct ufs_desc_size desc_size;
+
+	struct device_attribute ahibern8_attr;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f60145d4a66e..3bf8826318b0 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -48,7 +48,7 @@  enum {
 	REG_UFS_VERSION				= 0x08,
 	REG_CONTROLLER_DEV_ID			= 0x10,
 	REG_CONTROLLER_PROD_ID			= 0x14,
-	REG_AUTO_HIBERNATE_IDLE_TIMER		= 0x18,
+	REG_AUTO_HIBERN8_IDLE_TIMER		= 0x18,
 	REG_INTERRUPT_STATUS			= 0x20,
 	REG_INTERRUPT_ENABLE			= 0x24,
 	REG_CONTROLLER_STATUS			= 0x30,
@@ -86,6 +86,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 +137,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)
 
@@ -428,4 +429,18 @@  struct utp_task_req_desc {
 	__le32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS];
 };
 
+enum {
+	UFSHCI_AHIBERN8_SCALE_1US	= 0,
+	UFSHCI_AHIBERN8_SCALE_10US	= 1,
+	UFSHCI_AHIBERN8_SCALE_100US	= 2,
+	UFSHCI_AHIBERN8_SCALE_1MS	= 3,
+	UFSHCI_AHIBERN8_SCALE_10MS	= 4,
+	UFSHCI_AHIBERN8_SCALE_100MS	= 5,
+	UFSHCI_AHIBERN8_SCALE_MAX,
+};
+
+#define UFSHCI_AHIBERN8_TIMER_MASK		0x03ff
+#define UFSHCI_AHIBERN8_SCALE_MASK		0x1C00
+#define UFSHCI_AHIBERN8_SCALE_OFFSET		10
+
 #endif /* End of Header */