Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mmc: rtsx: reset power state on suspend

When rtsx_pci suspends, the card reader hardware powers off but the sdmmc
driver's prev_power_state remains as MMC_POWER_ON. This causes sd_power_on
to skip reinitialization on the next I/O request, leading to DMA transfer
timeouts and errors on resume 20% of the time.

Add a power_off slot callback so the PCR can notify the sdmmc driver
during suspend. The sdmmc driver resets prev_power_state, and sd_request
checks this to reinitialize the card before the next I/O.

Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Link: https://patch.msgid.link/20260105060236.400366-2-matthew.schwartz@linux.dev
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Matthew Schwartz and committed by
Greg Kroah-Hartman
eac85fbd 5f0bf80c

+32
+9
drivers/misc/cardreader/rtsx_pcr.c
··· 1654 1654 struct pci_dev *pcidev = to_pci_dev(dev_d); 1655 1655 struct pcr_handle *handle = pci_get_drvdata(pcidev); 1656 1656 struct rtsx_pcr *pcr = handle->pcr; 1657 + struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD]; 1657 1658 1658 1659 dev_dbg(&(pcidev->dev), "--> %s\n", __func__); 1659 1660 1660 1661 cancel_delayed_work_sync(&pcr->carddet_work); 1661 1662 1662 1663 mutex_lock(&pcr->pcr_mutex); 1664 + 1665 + if (slot->p_dev && slot->power_off) 1666 + slot->power_off(slot->p_dev); 1663 1667 1664 1668 rtsx_pci_power_off(pcr, HOST_ENTER_S3, false); 1665 1669 ··· 1776 1772 struct pci_dev *pcidev = to_pci_dev(device); 1777 1773 struct pcr_handle *handle = pci_get_drvdata(pcidev); 1778 1774 struct rtsx_pcr *pcr = handle->pcr; 1775 + struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD]; 1779 1776 1780 1777 dev_dbg(device, "--> %s\n", __func__); 1781 1778 1782 1779 cancel_delayed_work_sync(&pcr->carddet_work); 1783 1780 1784 1781 mutex_lock(&pcr->pcr_mutex); 1782 + 1783 + if (slot->p_dev && slot->power_off) 1784 + slot->power_off(slot->p_dev); 1785 + 1785 1786 rtsx_pci_power_off(pcr, HOST_ENTER_S3, true); 1786 1787 1787 1788 mutex_unlock(&pcr->pcr_mutex);
+22
drivers/mmc/host/rtsx_pci_sdmmc.c
··· 47 47 }; 48 48 49 49 static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios); 50 + static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode); 50 51 51 52 static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) 52 53 { ··· 822 821 823 822 rtsx_pci_start_run(pcr); 824 823 824 + if (host->prev_power_state == MMC_POWER_OFF) { 825 + err = sd_power_on(host, MMC_POWER_ON); 826 + if (err) { 827 + cmd->error = err; 828 + mutex_unlock(&pcr->pcr_mutex); 829 + goto finish; 830 + } 831 + } 832 + 825 833 rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, 826 834 host->initial_mode, host->double_clk, host->vpclk); 827 835 rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, SD_MOD_SEL); ··· 1491 1481 mmc_detect_change(host->mmc, 0); 1492 1482 } 1493 1483 1484 + static void rtsx_pci_sdmmc_power_off(struct platform_device *pdev) 1485 + { 1486 + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); 1487 + 1488 + if (!host) 1489 + return; 1490 + 1491 + host->prev_power_state = MMC_POWER_OFF; 1492 + } 1493 + 1494 1494 static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) 1495 1495 { 1496 1496 struct mmc_host *mmc; ··· 1533 1513 platform_set_drvdata(pdev, host); 1534 1514 pcr->slots[RTSX_SD_CARD].p_dev = pdev; 1535 1515 pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; 1516 + pcr->slots[RTSX_SD_CARD].power_off = rtsx_pci_sdmmc_power_off; 1536 1517 1537 1518 mutex_init(&host->host_mutex); 1538 1519 ··· 1565 1544 pcr = host->pcr; 1566 1545 pcr->slots[RTSX_SD_CARD].p_dev = NULL; 1567 1546 pcr->slots[RTSX_SD_CARD].card_event = NULL; 1547 + pcr->slots[RTSX_SD_CARD].power_off = NULL; 1568 1548 mmc = host->mmc; 1569 1549 1570 1550 cancel_work_sync(&host->work);
+1
include/linux/rtsx_common.h
··· 32 32 struct rtsx_slot { 33 33 struct platform_device *p_dev; 34 34 void (*card_event)(struct platform_device *p_dev); 35 + void (*power_off)(struct platform_device *p_dev); 35 36 }; 36 37 37 38 #endif