From nobody Fri Oct 10 02:41:50 2025 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CF8DA28E594 for ; Mon, 16 Jun 2025 10:29:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.203.201.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750069763; cv=none; b=mRdNFMgRjzwARaw2RYBtDh9UTnoLdgOQ7A5hRgUsOvSEEnJcbPp6JyDJNdp8SWY3PRtYLCYTdiyzDTEmdNrZ8+pUbDmOYGjVZVgkJbqPdMdH0VON51jcZY+ktqIEI3uxE4QZzRohp+J+Fn2KldqD8sDDOnxo3QjdrKD+G3NyJNs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1750069763; c=relaxed/simple; bh=m5hcZ5y48d+2Z8bAMd+te/qHD+psMsZlibq4f9Qo/s0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ZgiRT9njdpOMojPn+ZlU9qRJUePIyPJpMGCQc/AXCRE96G/8AvdLNcc8ImiGq1Mtc1tWhBM/F9BPhW0BRCr1EdudzwBF0kG/IXPRzmZmxA3TXqL2YW40Br4Mxec0U30G2BSBFqveMaGSOvgs8LoSQmu+q9oLSwk8dq/hd0nH6yA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de; spf=pass smtp.mailfrom=pengutronix.de; arc=none smtp.client-ip=185.203.201.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1uR75b-0008T2-0A; Mon, 16 Jun 2025 12:29:19 +0200 Received: from dude04.red.stw.pengutronix.de ([2a0a:edc0:0:1101:1d::ac]) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1uR75a-003n2z-0a; Mon, 16 Jun 2025 12:29:18 +0200 Received: from ore by dude04.red.stw.pengutronix.de with local (Exim 4.96) (envelope-from ) id 1uR75a-0072JF-0J; Mon, 16 Jun 2025 12:29:18 +0200 From: Oleksij Rempel To: Ulf Hansson Cc: Oleksij Rempel , kernel@pengutronix.de, linux-kernel@vger.kernel.org, linux-mmc@vger.kernel.org, Greg Kroah-Hartman , Mark Brown , "Rafael J. Wysocki" , =?UTF-8?q?S=C3=B8ren=20Andersen?= , Christian Loehle , Adrian Hunter , Avri Altman Subject: [PATCH v6 3/4] mmc: core: add undervoltage handler for MMC/eMMC devices Date: Mon, 16 Jun 2025 12:29:16 +0200 Message-Id: <20250616102917.1677116-4-o.rempel@pengutronix.de> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250616102917.1677116-1-o.rempel@pengutronix.de> References: <20250616102917.1677116-1-o.rempel@pengutronix.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: ore@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Introduce `_mmc_handle_undervoltage()` to handle undervoltage events for MMC/eMMC devices. The handler performs a controlled emergency suspend and then marks the card as removed to prevent further I/O. This is achieved by calling a new internal helper, `__mmc_suspend()`, with `MMC_POWEROFF_UNDERVOLTAGE`. This ensures a fast power-down sequence by using the short power-off notification and skipping the cache flush. If power-off notify is not supported, it falls back to sleep or deselect. Signed-off-by: Oleksij Rempel --- changes v6: - Refactor suspend logic: move cache flush skipping during undervoltage to a separate, preceding commit. - update commit message changes v5: - Rebased on top of patch introducing enum mmc_poweroff_type - Updated call to __mmc_suspend() to use MMC_POWEROFF_UNDERVOLTAGE - Dropped __mmc_resume() helper, as it is no longer needed - Updated commit message to reflect API change and code removal changes v4: - Drop HPI step. changes v3: - reword commit message. - add comments in the code - do not try to resume sleeping device --- drivers/mmc/core/mmc.c | 76 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6812df679ba9..fe4fc2ad261e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2120,7 +2120,7 @@ static int _mmc_flush_cache(struct mmc_host *host) return err; } =20 -static int _mmc_suspend(struct mmc_host *host, enum mmc_poweroff_type pm_t= ype) +static int __mmc_suspend(struct mmc_host *host, enum mmc_poweroff_type pm_= type) { unsigned int notify_type =3D EXT_CSD_POWER_OFF_SHORT; int err =3D 0; @@ -2128,8 +2128,6 @@ static int _mmc_suspend(struct mmc_host *host, enum m= mc_poweroff_type pm_type) if (pm_type =3D=3D MMC_POWEROFF_SHUTDOWN) notify_type =3D EXT_CSD_POWER_OFF_LONG; =20 - mmc_claim_host(host); - if (mmc_card_suspended(host->card)) goto out; =20 @@ -2156,7 +2154,17 @@ static int _mmc_suspend(struct mmc_host *host, enum = mmc_poweroff_type pm_type) mmc_card_set_suspended(host->card); } out: + return err; +} + +static int _mmc_suspend(struct mmc_host *host, enum mmc_poweroff_type pm_t= ype) +{ + int err; + + mmc_claim_host(host); + err =3D __mmc_suspend(host, pm_type); mmc_release_host(host); + return err; } =20 @@ -2219,6 +2227,13 @@ static int mmc_shutdown(struct mmc_host *host) { int err =3D 0; =20 + /* + * In case of undervoltage, the card will be powered off by + * _mmc_handle_undervoltage() + */ + if (host->undervoltage) + return 0; + /* * If the card remains suspended at this point and it was done by using * the sleep-cmd (CMD5), we may need to re-initialize it first, to allow @@ -2309,6 +2324,60 @@ static int _mmc_hw_reset(struct mmc_host *host) return mmc_init_card(host, card->ocr, card); } =20 +/** + * _mmc_handle_undervoltage - Handle an undervoltage event for MMC/eMMC de= vices + * @host: MMC host structure + * + * This function is triggered when an undervoltage condition is detected. + * It attempts to transition the device into a low-power or safe state to + * prevent data corruption. + * + * Steps performed: + * 1. If no card is present, return immediately. + * 2. Perform an emergency suspend using EXT_CSD_POWER_OFF_SHORT if possib= le. + * - If power-off notify is not supported, fallback mechanisms like sle= ep or + * deselecting the card are attempted. + * - Cache flushing is skipped to reduce execution time. + * 3. Mark the card as removed to prevent further interactions after + * undervoltage. + * + * Note: This function does not handle host claiming or releasing. The cal= ler + * must ensure that the host is properly claimed before calling this + * function and released afterward. + * + * Returns: 0 on success, or a negative error code if any step fails. + */ +static int _mmc_handle_undervoltage(struct mmc_host *host) +{ + struct mmc_card *card =3D host->card; + int err; + + /* If there is no card attached, nothing to do */ + if (!card) + return 0; + + /* + * Perform an emergency suspend to power off the eMMC quickly. + * This ensures the device enters a safe state before power is lost. + * We first attempt EXT_CSD_POWER_OFF_SHORT, but if power-off notify + * is not supported, we fall back to sleep mode or deselecting the card. + * Cache flushing is skipped to minimize delay. + */ + err =3D __mmc_suspend(host, MMC_POWEROFF_UNDERVOLTAGE); + if (err) + pr_err("%s: undervoltage suspend failed: %pe\n", + mmc_hostname(host), ERR_PTR(err)); + + /* + * Mark the card as removed to prevent further operations. + * This ensures the system does not attempt to access the device + * after an undervoltage event, avoiding potential corruption. + */ + mmc_card_set_removed(card); + + return err; +} + static const struct mmc_bus_ops mmc_ops =3D { .remove =3D mmc_remove, .detect =3D mmc_detect, @@ -2321,6 +2390,7 @@ static const struct mmc_bus_ops mmc_ops =3D { .hw_reset =3D _mmc_hw_reset, .cache_enabled =3D _mmc_cache_enabled, .flush_cache =3D _mmc_flush_cache, + .handle_undervoltage =3D _mmc_handle_undervoltage, }; =20 /* --=20 2.39.5