lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251025160905.3857885-388-sashal@kernel.org>
Date: Sat, 25 Oct 2025 12:00:19 -0400
From: Sasha Levin <sashal@...nel.org>
To: patches@...ts.linux.dev,
	stable@...r.kernel.org
Cc: Peter Wang <peter.wang@...iatek.com>,
	"Martin K. Petersen" <martin.petersen@...cle.com>,
	Sasha Levin <sashal@...nel.org>,
	matthias.bgg@...il.com,
	angelogioacchino.delregno@...labora.com,
	linux-scsi@...r.kernel.org,
	linux-mediatek@...ts.infradead.org,
	linux-kernel@...r.kernel.org,
	linux-arm-kernel@...ts.infradead.org
Subject: [PATCH AUTOSEL 6.17-6.6] scsi: ufs: host: mediatek: Fix auto-hibern8 timer configuration

From: Peter Wang <peter.wang@...iatek.com>

[ Upstream commit aa86602a483ba48f51044fbaefa1ebbf6da194a4 ]

Move the configuration of the Auto-Hibern8 (AHIT) timer from the
post-link stage to the 'fixup_dev_quirks' function. This change allows
setting the AHIT based on the vendor requirements:

   (a) Samsung: 3.5 ms
   (b) Micron: 2 ms
   (c) Others: 1 ms

Additionally, the clock gating timer is adjusted based on the AHIT
scale, with a maximum setting of 10 ms. This ensures that the clock
gating delay is appropriately configured to match the AHIT settings.

Signed-off-by: Peter Wang <peter.wang@...iatek.com>
Link: https://lore.kernel.org/r/20250811131423.3444014-3-peter.wang@mediatek.com
Signed-off-by: Martin K. Petersen <martin.petersen@...cle.com>
Signed-off-by: Sasha Levin <sashal@...nel.org>
---

LLM Generated explanations, may be completely bogus:

YES

- Fixes a real bug affecting users. Today the driver unconditionally
  programs AH8 to 10 ms during link bring-up and derives the clock-
  gating delay from only the AHIT timer field, ignoring the scale. That
  yields incorrect behavior when a device needs a vendor-specific AH8
  value or when the AHIT scale is not 1 ms. The patch:
  - Removes the hardcoded AH8 value from `ufs_mtk_post_link()` in
    `drivers/ufs/host/ufs-mediatek.c` and defers programming until
    device info is known.
  - Adds `ufs_mtk_fix_ahit()` to set `hba->ahit` based on the UFS
    vendor: Samsung 3.5 ms, Micron 2 ms, others 1 ms.
  - Introduces `ufs_mtk_us_to_ahit()` so the AHIT encoding matches the
    HCI (same logic as the core sysfs helper).
  - Reworks `ufs_mtk_setup_clk_gating()` to derive the delay from the
    full AHIT value (timer + scale), avoiding the previous scale bug.

- Correct stage for AHIT programming. Moving the AHIT setup from link
  POST_CHANGE to the device-quirk fixup stage is correct because the
  vendor ID isn’t known at `POST_CHANGE`. The fix happens in
  `ufs_mtk_fixup_dev_quirks()` which runs after reading device
  descriptors (see core flow in `drivers/ufs/core/ufshcd.c:8380` calling
  `ufs_fixup_device_setup(hba)`), and before the core writes AHIT to
  hardware (`ufshcd_configure_auto_hibern8()` at
  `drivers/ufs/core/ufshcd.c:8967`). Hence the right AHIT gets
  programmed without extra transitions.

- Fixes a concrete correctness issue in clock-gating. Previously
  `ufs_mtk_setup_clk_gating()` computed the delay as `ah_ms =
  FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, hba->ahit)` and then
  `ufshcd_clkgate_delay_set(..., ah_ms + 5)`. That ignores the AHIT
  scale and is only correct if the scale is 1 ms (which the driver
  forcibly set earlier). The patch:
  - Parses both AHIT scale and timer and converts to milliseconds via a
    `scale_us[]` table before setting the gating delay. This fixes
    gating delay when vendors require non-ms scales.
  - Sets a minimum gating delay of 10 ms (`delay_ms = max(ah_ms, 10U)`)
    to avoid overly aggressive gating when AHIT is small (1–3.5 ms).
    This is a conservative, low-risk change that reduces churn.

- Small, contained change with minimal regression risk.
  - Scope: one driver file (`drivers/ufs/host/ufs-mediatek.c`), no API
    or architectural changes.
  - Behavior: only affects Mediatek UFS host behavior and only when AH8
    is supported and enabled.
  - The vendor-based AHIT values are bounded and modest (1–3.5 ms), and
    the gating floor of 10 ms is conservative.
  - The patch respects `ufshcd_is_auto_hibern8_supported()` and won’t
    alter systems where AH8 is disabled (driver already handles
    disabling AH8; see `drivers/ufs/host/ufs-mediatek.c:258`).

- Alignment with core defaults and flow. The core sets a default AHIT
  (150 ms) only if none is set earlier
  (`drivers/ufs/core/ufshcd.c:10679`). The mediatek driver previously
  overwrote this to 10 ms unconditionally at `POST_CHANGE`. The new
  approach correctly overrides the default with vendor-specific AHIT at
  quirk-fixup time and before the core writes the register, making the
  effective setting both correct and deterministic.

- Backport notes and considerations.
  - The quirk-fixup hook must be present in the target stable branch
    (`ufshcd_vops_fixup_dev_quirks()` and call site exist in current
    stable series; see `drivers/ufs/core/ufshcd-priv.h:195` and
    `drivers/ufs/core/ufshcd.c:8380`).
  - The helper macros and fields used (e.g., `UFSHCI_AHIBERN8_*`,
    `UFS_VENDOR_*`, `hba->clk_gating.delay_ms`) are present in
    maintained stable branches.
  - Minor nits: the patch updates `hba->clk_gating.delay_ms` under
    `host->host_lock` instead of using `ufshcd_clkgate_delay_set()`,
    which in core protects the assignment with `clk_gating.lock`.
    Functionally it’s fine for a single-word store, but for consistency
    you may prefer `ufshcd_clkgate_delay_set(hba->dev, max(ah_ms, 10U))`
    when backporting to preserve locking semantics.
  - The commit message says “maximum setting of 10 ms,” but the code
    enforces a minimum of 10 ms via `max(ah_ms, 10U)`. The
    implementation is the safer choice and aligns with the intent to
    avoid too-aggressive gating.

Conclusion: This is a targeted bug fix that corrects AHIT configuration
timing, applies vendor requirements, and fixes the gating-delay
calculation to account for AHIT scale. It’s small, self-contained, and
low risk. It is suitable for backporting to stable kernel trees.

 drivers/ufs/host/ufs-mediatek.c | 86 ++++++++++++++++++++++++---------
 1 file changed, 64 insertions(+), 22 deletions(-)

diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c
index f902ce08c95a6..8dd124835151a 100644
--- a/drivers/ufs/host/ufs-mediatek.c
+++ b/drivers/ufs/host/ufs-mediatek.c
@@ -1075,6 +1075,69 @@ static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
 	}
 }
 
+static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
+{
+	unsigned long flags;
+	u32 ah_ms = 10;
+	u32 ah_scale, ah_timer;
+	u32 scale_us[] = {1, 10, 100, 1000, 10000, 100000};
+
+	if (ufshcd_is_clkgating_allowed(hba)) {
+		if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit) {
+			ah_scale = FIELD_GET(UFSHCI_AHIBERN8_SCALE_MASK,
+					  hba->ahit);
+			ah_timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
+					  hba->ahit);
+			if (ah_scale <= 5)
+				ah_ms = ah_timer * scale_us[ah_scale] / 1000;
+		}
+
+		spin_lock_irqsave(hba->host->host_lock, flags);
+		hba->clk_gating.delay_ms = max(ah_ms, 10U);
+		spin_unlock_irqrestore(hba->host->host_lock, flags);
+	}
+}
+
+/* Convert microseconds to Auto-Hibernate Idle Timer register value */
+static u32 ufs_mtk_us_to_ahit(unsigned int timer)
+{
+	unsigned int scale;
+
+	for (scale = 0; timer > UFSHCI_AHIBERN8_TIMER_MASK; ++scale)
+		timer /= UFSHCI_AHIBERN8_SCALE_FACTOR;
+
+	return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) |
+	       FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale);
+}
+
+static void ufs_mtk_fix_ahit(struct ufs_hba *hba)
+{
+	unsigned int us;
+
+	if (ufshcd_is_auto_hibern8_supported(hba)) {
+		switch (hba->dev_info.wmanufacturerid) {
+		case UFS_VENDOR_SAMSUNG:
+			/* configure auto-hibern8 timer to 3.5 ms */
+			us = 3500;
+			break;
+
+		case UFS_VENDOR_MICRON:
+			/* configure auto-hibern8 timer to 2 ms */
+			us = 2000;
+			break;
+
+		default:
+			/* configure auto-hibern8 timer to 1 ms */
+			us = 1000;
+			break;
+		}
+
+		hba->ahit = ufs_mtk_us_to_ahit(us);
+	}
+
+	ufs_mtk_setup_clk_gating(hba);
+}
+
 static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
 {
 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
@@ -1369,32 +1432,10 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba)
 
 	return ret;
 }
-
-static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
-{
-	u32 ah_ms;
-
-	if (ufshcd_is_clkgating_allowed(hba)) {
-		if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit)
-			ah_ms = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
-					  hba->ahit);
-		else
-			ah_ms = 10;
-		ufshcd_clkgate_delay_set(hba->dev, ah_ms + 5);
-	}
-}
-
 static void ufs_mtk_post_link(struct ufs_hba *hba)
 {
 	/* enable unipro clock gating feature */
 	ufs_mtk_cfg_unipro_cg(hba, true);
-
-	/* will be configured during probe hba */
-	if (ufshcd_is_auto_hibern8_supported(hba))
-		hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) |
-			FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
-
-	ufs_mtk_setup_clk_gating(hba);
 }
 
 static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
@@ -1726,6 +1767,7 @@ static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
 
 	ufs_mtk_vreg_fix_vcc(hba);
 	ufs_mtk_vreg_fix_vccqx(hba);
+	ufs_mtk_fix_ahit(hba);
 }
 
 static void ufs_mtk_event_notify(struct ufs_hba *hba,
-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ