Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 03 Dec 2025 04:06:43 +0000
From:      Jaeyoon Choi <jaeyoon@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: db8b06468bae - main - ufshci: Support UIC Auto Hibernation
Message-ID:  <692fb753.395f5.57220ef9@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by jaeyoon:

URL: https://cgit.FreeBSD.org/src/commit/?id=db8b06468baefb9d9b5db5f91084d85071bfb5cb

commit db8b06468baefb9d9b5db5f91084d85071bfb5cb
Author:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2025-12-03 04:06:01 +0000
Commit:     Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2025-12-03 04:06:01 +0000

    ufshci: Support UIC Auto Hibernation
    
    Automatically transition the UniPro link to Hibernate when it is idle
    for the duration configured by the Auto-Hibernate Idle Timer (AHIT).
    This reduces link power while the device is inactive.
    
    Reviewed by:            imp (mentor)
    Sponsored by:           Samsung Electronics
    Differential Revision:  https://reviews.freebsd.org/D54004
---
 sys/dev/ufshci/ufshci_ctrlr.c   |  4 ++++
 sys/dev/ufshci/ufshci_dev.c     | 27 +++++++++++++++++++++++++++
 sys/dev/ufshci/ufshci_pci.c     |  3 ++-
 sys/dev/ufshci/ufshci_private.h |  9 +++++++++
 sys/dev/ufshci/ufshci_sysctl.c  | 28 ++++++++++++++++++++++++++++
 sys/dev/ufshci/ufshci_uic_cmd.c |  5 +++--
 6 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index 494313df95de..ce0da4cab907 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -92,6 +92,8 @@ ufshci_ctrlr_start(struct ufshci_controller *ctrlr, bool resetting)
 		return;
 	}
 
+	ufshci_dev_init_auto_hibernate(ctrlr);
+
 	/* TODO: Configure Write Protect */
 
 	/* TODO: Configure Background Operations */
@@ -674,5 +676,7 @@ ufshci_ctrlr_resume(struct ufshci_controller *ctrlr, enum power_stype stype)
 		}
 	}
 
+	ufshci_dev_enable_auto_hibernate(ctrlr);
+
 	return (0);
 }
diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c
index c4a5bda9c79a..38c6de9731a4 100644
--- a/sys/dev/ufshci/ufshci_dev.c
+++ b/sys/dev/ufshci/ufshci_dev.c
@@ -449,6 +449,33 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
 	return (0);
 }
 
+void
+ufshci_dev_enable_auto_hibernate(struct ufshci_controller *ctrlr)
+{
+	if (!ctrlr->ufs_dev.auto_hibernation_supported)
+		return;
+
+	ufshci_mmio_write_4(ctrlr, ahit, ctrlr->ufs_dev.ahit);
+}
+
+void
+ufshci_dev_init_auto_hibernate(struct ufshci_controller *ctrlr)
+{
+	ctrlr->ufs_dev.auto_hibernation_supported =
+	    UFSHCIV(UFSHCI_CAP_REG_AUTOH8, ctrlr->cap) &&
+	    !(ctrlr->quirks & UFSHCI_QUIRK_BROKEN_AUTO_HIBERNATE);
+
+	if (!ctrlr->ufs_dev.auto_hibernation_supported)
+		return;
+
+	/* The default value for auto hibernation is 150 ms */
+	ctrlr->ufs_dev.ahit = 0;
+	ctrlr->ufs_dev.ahit |= UFSHCIF(UFSHCI_AHIT_REG_AH8ITV, 150);
+	ctrlr->ufs_dev.ahit |= UFSHCIF(UFSHCI_AHIT_REG_TS, 3);
+
+	ufshci_dev_enable_auto_hibernate(ctrlr);
+}
+
 void
 ufshci_dev_init_uic_link_state(struct ufshci_controller *ctrlr)
 {
diff --git a/sys/dev/ufshci/ufshci_pci.c b/sys/dev/ufshci/ufshci_pci.c
index 5fce14997784..b2a958f1cd1a 100644
--- a/sys/dev/ufshci/ufshci_pci.c
+++ b/sys/dev/ufshci/ufshci_pci.c
@@ -58,7 +58,8 @@ static struct _pcsid {
 	    UFSHCI_REF_CLK_19_2MHz,
 	    UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE |
 		UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE |
-		UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY },
+		UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY |
+		UFSHCI_QUIRK_BROKEN_AUTO_HIBERNATE },
 	{ 0x54ff8086, "Intel UFS Host Controller", UFSHCI_REF_CLK_19_2MHz },
 	{ 0x00000000, NULL } };
 
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index 8a49c2a9bc2b..bcb2bcef0230 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -293,6 +293,10 @@ struct ufshci_device {
 	bool power_mode_supported;
 	enum ufshci_dev_pwr power_mode;
 	enum ufshci_uic_link_state link_state;
+
+	/* Auto Hibernation */
+	bool auto_hibernation_supported;
+	uint32_t ahit;
 };
 
 /*
@@ -314,6 +318,9 @@ struct ufshci_controller {
 	16 /* QEMU does not support Task Management Request */
 #define UFSHCI_QUIRK_SKIP_WELL_KNOWN_LUNS \
 	32 /* QEMU does not support Well known logical units*/
+#define UFSHCI_QUIRK_BROKEN_AUTO_HIBERNATE                                    \
+	64 /* Some controllers have the Auto hibernate feature enabled but it \
+	      does not work. */
 
 	uint32_t ref_clk;
 
@@ -457,6 +464,8 @@ int ufshci_dev_init(struct ufshci_controller *ctrlr);
 int ufshci_dev_reset(struct ufshci_controller *ctrlr);
 int ufshci_dev_init_reference_clock(struct ufshci_controller *ctrlr);
 int ufshci_dev_init_unipro(struct ufshci_controller *ctrlr);
+void ufshci_dev_enable_auto_hibernate(struct ufshci_controller *ctrlr);
+void ufshci_dev_init_auto_hibernate(struct ufshci_controller *ctrlr);
 int ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr);
 void ufshci_dev_init_uic_link_state(struct ufshci_controller *ctrlr);
 int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr);
diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c
index 30b0ccaeed13..495f087f3c50 100644
--- a/sys/dev/ufshci/ufshci_sysctl.c
+++ b/sys/dev/ufshci/ufshci_sysctl.c
@@ -11,6 +11,7 @@
 #include <sys/sysctl.h>
 
 #include "ufshci_private.h"
+#include "ufshci_reg.h"
 
 static int
 ufshci_sysctl_timeout_period(SYSCTL_HANDLER_ARGS)
@@ -106,6 +107,22 @@ ufshci_sysctl_num_failures(SYSCTL_HANDLER_ARGS)
 	return (sysctl_handle_64(oidp, &num_failures, 0, req));
 }
 
+static int
+ufshci_sysctl_ahit(SYSCTL_HANDLER_ARGS)
+{
+	struct ufshci_controller *ctrlr = arg1;
+	int64_t scale, timer;
+	const int64_t scale_factor = 10;
+
+	scale = UFSHCIV(UFSHCI_AHIT_REG_TS, ctrlr->ufs_dev.ahit);
+	timer = UFSHCIV(UFSHCI_AHIT_REG_AH8ITV, ctrlr->ufs_dev.ahit);
+
+	while (scale--)
+		timer *= scale_factor;
+
+	return (sysctl_handle_64(oidp, &timer, 0, req));
+}
+
 static void
 ufshci_sysctl_initialize_queue(struct ufshci_hw_queue *hwq,
     struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree)
@@ -201,6 +218,17 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr)
 	    CTLFLAG_RD, &dev->power_mode_supported, 0,
 	    "Device power mode support");
 
+	SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO,
+	    "auto_hibernation_supported", CTLFLAG_RD,
+	    &dev->auto_hibernation_supported, 0,
+	    "Device auto hibernation support");
+
+	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
+	    "auto_hibernate_idle_timer_value",
+	    CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE, ctrlr, 0,
+	    ufshci_sysctl_ahit, "IU",
+	    "Auto-Hibernate Idle Timer Value (in microseconds)");
+
 	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "power_mode",
 	    CTLFLAG_RD, &dev->power_mode, 0, "Current device power mode");
 
diff --git a/sys/dev/ufshci/ufshci_uic_cmd.c b/sys/dev/ufshci/ufshci_uic_cmd.c
index 29c143cec52c..c6e6afe3f688 100644
--- a/sys/dev/ufshci/ufshci_uic_cmd.c
+++ b/sys/dev/ufshci/ufshci_uic_cmd.c
@@ -196,8 +196,9 @@ ufshci_uic_send_cmd(struct ufshci_controller *ctrlr,
 	config_result_code = ufshci_mmio_read_4(ctrlr, ucmdarg2);
 	if (config_result_code) {
 		ufshci_printf(ctrlr,
-		    "Failed to send UIC command. (config result code = 0x%x)\n",
-		    config_result_code);
+		    "Failed to send UIC command (Opcode: 0x%x"
+		    ", config result code = 0x%x)\n",
+		    uic_cmd->opcode, config_result_code);
 	}
 
 	if (return_value != NULL)


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?692fb753.395f5.57220ef9>