From: Sarthak Garg quic_sartgarg@quicinc.com
[ Upstream commit db58532188ebf51d52b1d7693d9e94c76b926e9f ]
Many mobile phones feature multi-card tray designs, where the same tray is used for both SD and SIM cards. If the SD card is placed at the outermost location in the tray, the SIM card may come in contact with SD card power-supply while removing the tray, possibly resulting in SIM damage.
To prevent that, make sure the SD card is really inserted by reading the Card Detect pin state. If it's not, turn off the power in sdhci_msm_check_power_status() and also set the BUS_FAIL power state on the controller as part of pwr_irq handling for BUS_ON request.
Signed-off-by: Sarthak Garg quic_sartgarg@quicinc.com Acked-by: Adrian Hunter adrian.hunter@intel.com Link: https://lore.kernel.org/r/20250701100659.3310386-1-quic_sartgarg@quicinc.com Signed-off-by: Ulf Hansson ulf.hansson@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
**Backport Status: YES**
This commit should be backported to stable kernel trees for the following reasons:
1. **Hardware Damage Prevention**: This is a critical safety fix that prevents potential hardware damage to SIM cards. The commit message clearly describes a real-world scenario where SD card power can damage SIM cards in multi-card tray designs when the tray is removed. This is a serious hardware safety issue that affects end users' devices.
2. **Bug Fix Nature**: The commit fixes a specific bug where SD card power remains ON even when the card is physically removed. The code changes show two key additions: - In `sdhci_msm_check_power_status()`: Added check at lines 1625-1629 that turns off power (writes 0 to SDHCI_POWER_CONTROL) when card is not detected (`!mmc->ops->get_cd(mmc)`) - In `sdhci_msm_handle_pwr_irq()`: Added check at lines 1689-1694 that sets BUS_FAIL state when attempting to power on the bus while card is not present
3. **Small and Contained Fix**: The changes are minimal and well- contained: - Only 13 lines of actual code changes - Changes are localized to the sdhci-msm driver - No architectural changes or new features - Simple logic additions that check card presence before power operations
4. **Low Risk of Regression**: The fix adds defensive checks that only activate when: - A card is physically not present (detected via get_cd) - Power operations are being performed - This doesn't affect normal operation when cards are properly inserted
5. **Platform-Specific Critical Fix**: This affects Qualcomm MSM-based devices which are widely used in mobile phones. The multi-card tray design mentioned is common in many smartphones, making this a widespread potential issue.
6. **Clear Problem and Solution**: The commit has a clear problem statement (SIM damage from SD power) and a straightforward solution (turn off power when card is removed). This makes it easy to verify the fix is correct.
The commit follows stable tree rules perfectly - it's a important bugfix that prevents hardware damage, has minimal code changes, doesn't introduce new features, and has very low regression risk. This is exactly the type of safety-critical fix that stable kernels should include.
drivers/mmc/host/sdhci-msm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 66c0d1ba2a33..bc6ca49652f8 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1564,6 +1564,7 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; bool done = false; u32 val = SWITCHABLE_SIGNALING_VOLTAGE; const struct sdhci_msm_offset *msm_offset = @@ -1621,6 +1622,12 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) "%s: pwr_irq for req: (%d) timed out\n", mmc_hostname(host->mmc), req_type); } + + if ((req_type & REQ_BUS_ON) && mmc->card && !mmc->ops->get_cd(mmc)) { + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + host->pwr = 0; + } + pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), __func__, req_type); } @@ -1679,6 +1686,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) udelay(10); }
+ if ((irq_status & CORE_PWRCTL_BUS_ON) && mmc->card && + !mmc->ops->get_cd(mmc)) { + msm_host_writel(msm_host, CORE_PWRCTL_BUS_FAIL, host, + msm_offset->core_pwrctl_ctl); + return; + } + /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { pwr_state = REQ_BUS_ON;