Linux MultiMedia Card development
 help / color / mirror / Atom feed
* [PATCH] mmc: rtsx_pci: Cope with hot-removal of MMC host
@ 2026-08-15  8:10 Lukas Wunner
  2026-09-08 15:38 ` Ulf Hansson
  0 siblings, 1 reply; 3+ messages in thread
From: Lukas Wunner @ 2026-08-15  8:10 UTC (permalink / raw)
  To: Ulf Hansson, Ricky Wu
  Cc: Derek J. Clark, Matthew Schwartz, Pierre-Loup A. Griffais,
	linux-mmc, Christoph Hellwig, Keith Busch

Derek reports a lockup on hot-removal of a PCI-attached Realtek RTS525A
MMC host if a card is inserted.  He has root-caused it to the block
layer being unaware of the hot-removal and waiting indefinitely in
sync_filesystem().

For comparison, the NVMe subsystem copes with hot-removal by setting the
controller state to NVME_CTRL_DEAD in nvme_remove(), which in turn leads
to blk_mark_disk_dead() being called from nvme_mark_namespaces_dead().
That avoids the indefinite wait in sync_filesystem().

Adopt this approach:  Detect hot-removal in rtsx_pci_sdmmc_drv_remove()
and invoke a new mmc_host_set_removed() helper which in turn invokes
mmc_card_set_removed().  Before flushing outstanding requests to the
card in mmc_blk_remove_req(), check for its removal and call
blk_mark_disk_dead().

Note that mmc_card_set_removed() cannot be called from the MMC host
driver because it is private to the MMC core, hence the indirection
through the newly introduced mmc_host_set_removed() helper.

Other removable MMC hosts, in particular if attached via PCI or USB,
may need to be amended with a similar check for hot-removal.  The
present commit seeks to get that process going.

Reported-by: Derek J. Clark <derekjohn.clark@gmail.com>
Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
Closes: https://lore.kernel.org/r/20260806214808.1202819-1-derekjohn.clark@gmail.com/
Link: https://github.com/ValveSoftware/SteamOS/issues/2473
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: Matthew Schwartz <matthew.schwartz@linux.dev>
---
 drivers/mmc/core/block.c          | 11 +++++++----
 drivers/mmc/core/host.c           | 15 +++++++++++++++
 drivers/mmc/host/rtsx_pci_sdmmc.c |  3 +++
 include/linux/mmc/host.h          |  1 +
 4 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 0274e8d..1a82233 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -2978,8 +2978,11 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
 	return 0;
 }
 
-static void mmc_blk_remove_req(struct mmc_blk_data *md)
+static void mmc_blk_remove_req(struct mmc_card *card, struct mmc_blk_data *md)
 {
+	if (mmc_card_removed(card))
+		blk_mark_disk_dead(md->disk);
+
 	/*
 	 * Flush remaining requests and free queues. It is freeing the queue
 	 * that stops new requests from being accepted.
@@ -3006,7 +3009,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
 	list_for_each_safe(pos, q, &md->part) {
 		part_md = list_entry(pos, struct mmc_blk_data, part);
 		list_del(pos);
-		mmc_blk_remove_req(part_md);
+		mmc_blk_remove_req(card, part_md);
 	}
 }
 
@@ -3252,7 +3255,7 @@ static int mmc_blk_probe(struct mmc_card *card)
 
 out:
 	mmc_blk_remove_parts(card, md);
-	mmc_blk_remove_req(md);
+	mmc_blk_remove_req(card, md);
 out_free:
 	destroy_workqueue(card->complete_wq);
 	return ret;
@@ -3273,7 +3276,7 @@ static void mmc_blk_remove(struct mmc_card *card)
 	if (!mmc_card_sd_combo(card))
 		pm_runtime_disable(&card->dev);
 	pm_runtime_put_noidle(&card->dev);
-	mmc_blk_remove_req(md);
+	mmc_blk_remove_req(card, md);
 	destroy_workqueue(card->complete_wq);
 }
 
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index b7ce313..2625d91 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -22,6 +22,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/slot-gpio.h>
 
+#include "card.h"
 #include "core.h"
 #include "crypto.h"
 #include "host.h"
@@ -703,3 +704,17 @@ void mmc_free_host(struct mmc_host *host)
 }
 
 EXPORT_SYMBOL(mmc_free_host);
+
+/**
+ *	mmc_host_set_removed - declare host removed
+ *	@host: mmc host
+ *
+ *	Declare the host (and any inserted card) removed and inaccessible.
+ */
+void mmc_host_set_removed(struct mmc_host *host)
+{
+	if (host->card)
+		mmc_card_set_removed(host->card);
+}
+
+EXPORT_SYMBOL(mmc_host_set_removed);
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 8dfbc62..3f97659f 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -1511,6 +1511,9 @@ static void rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
 	mmc = host->mmc;
 
+	if (pci_dev_is_disconnected(pcr->pci))
+		mmc_host_set_removed(mmc);
+
 	cancel_work_sync(&host->work);
 
 	mutex_lock(&host->host_mutex);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ba84f02..a240306 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -588,6 +588,7 @@ struct mmc_host {
 int mmc_add_host(struct mmc_host *);
 void mmc_remove_host(struct mmc_host *);
 void mmc_free_host(struct mmc_host *);
+void mmc_host_set_removed(struct mmc_host *host);
 void mmc_of_parse_clk_phase(struct device *dev,
 			    struct mmc_clk_phase_map *map);
 int mmc_of_parse(struct mmc_host *host);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] mmc: rtsx_pci: Cope with hot-removal of MMC host
  2026-08-15  8:10 [PATCH] mmc: rtsx_pci: Cope with hot-removal of MMC host Lukas Wunner
@ 2026-09-08 15:38 ` Ulf Hansson
  2026-09-08 16:30   ` Lukas Wunner
  0 siblings, 1 reply; 3+ messages in thread
From: Ulf Hansson @ 2026-09-08 15:38 UTC (permalink / raw)
  To: lukas
  Cc: Ulf Hansson, Ricky Wu, Derek J. Clark, Matthew Schwartz,
	Pierre-Loup A. Griffais, linux-mmc, Christoph Hellwig,
	Keith Busch

On Sat, Aug 15, 2026 at 10:10 AM Lukas Wunner <lukas@wunner.de> wrote:
>
> Derek reports a lockup on hot-removal of a PCI-attached Realtek RTS525A
> MMC host if a card is inserted.  He has root-caused it to the block
> layer being unaware of the hot-removal and waiting indefinitely in
> sync_filesystem().

Is this specific for a PCI based mmc host?

Can this be triggered by just removing a removable SD card?

>
> For comparison, the NVMe subsystem copes with hot-removal by setting the
> controller state to NVME_CTRL_DEAD in nvme_remove(), which in turn leads
> to blk_mark_disk_dead() being called from nvme_mark_namespaces_dead().
> That avoids the indefinite wait in sync_filesystem().
>
> Adopt this approach:  Detect hot-removal in rtsx_pci_sdmmc_drv_remove()
> and invoke a new mmc_host_set_removed() helper which in turn invokes
> mmc_card_set_removed().  Before flushing outstanding requests to the
> card in mmc_blk_remove_req(), check for its removal and call
> blk_mark_disk_dead().

I need more information to understand the problem and whether the NVMe
approach is really suitable here.

What do other block subsystems do?

>
> Note that mmc_card_set_removed() cannot be called from the MMC host
> driver because it is private to the MMC core, hence the indirection
> through the newly introduced mmc_host_set_removed() helper.
>
> Other removable MMC hosts, in particular if attached via PCI or USB,
> may need to be amended with a similar check for hot-removal.  The
> present commit seeks to get that process going.

So it's specific for USB and PCI, why?

>
> Reported-by: Derek J. Clark <derekjohn.clark@gmail.com>
> Tested-by: Derek J. Clark <derekjohn.clark@gmail.com>
> Closes: https://lore.kernel.org/r/20260806214808.1202819-1-derekjohn.clark@gmail.com/
> Link: https://github.com/ValveSoftware/SteamOS/issues/2473
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> Cc: Matthew Schwartz <matthew.schwartz@linux.dev>
> ---
>  drivers/mmc/core/block.c          | 11 +++++++----
>  drivers/mmc/core/host.c           | 15 +++++++++++++++
>  drivers/mmc/host/rtsx_pci_sdmmc.c |  3 +++
>  include/linux/mmc/host.h          |  1 +
>  4 files changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
> index 0274e8d..1a82233 100644
> --- a/drivers/mmc/core/block.c
> +++ b/drivers/mmc/core/block.c
> @@ -2978,8 +2978,11 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
>         return 0;
>  }
>
> -static void mmc_blk_remove_req(struct mmc_blk_data *md)
> +static void mmc_blk_remove_req(struct mmc_card *card, struct mmc_blk_data *md)
>  {
> +       if (mmc_card_removed(card))
> +               blk_mark_disk_dead(md->disk);
> +
>         /*
>          * Flush remaining requests and free queues. It is freeing the queue
>          * that stops new requests from being accepted.
> @@ -3006,7 +3009,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
>         list_for_each_safe(pos, q, &md->part) {
>                 part_md = list_entry(pos, struct mmc_blk_data, part);
>                 list_del(pos);
> -               mmc_blk_remove_req(part_md);
> +               mmc_blk_remove_req(card, part_md);
>         }
>  }
>
> @@ -3252,7 +3255,7 @@ static int mmc_blk_probe(struct mmc_card *card)
>
>  out:
>         mmc_blk_remove_parts(card, md);
> -       mmc_blk_remove_req(md);
> +       mmc_blk_remove_req(card, md);
>  out_free:
>         destroy_workqueue(card->complete_wq);
>         return ret;
> @@ -3273,7 +3276,7 @@ static void mmc_blk_remove(struct mmc_card *card)
>         if (!mmc_card_sd_combo(card))
>                 pm_runtime_disable(&card->dev);
>         pm_runtime_put_noidle(&card->dev);
> -       mmc_blk_remove_req(md);
> +       mmc_blk_remove_req(card, md);
>         destroy_workqueue(card->complete_wq);
>  }
>
> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
> index b7ce313..2625d91 100644
> --- a/drivers/mmc/core/host.c
> +++ b/drivers/mmc/core/host.c
> @@ -22,6 +22,7 @@
>  #include <linux/mmc/card.h>
>  #include <linux/mmc/slot-gpio.h>
>
> +#include "card.h"
>  #include "core.h"
>  #include "crypto.h"
>  #include "host.h"
> @@ -703,3 +704,17 @@ void mmc_free_host(struct mmc_host *host)
>  }
>
>  EXPORT_SYMBOL(mmc_free_host);
> +
> +/**
> + *     mmc_host_set_removed - declare host removed
> + *     @host: mmc host
> + *
> + *     Declare the host (and any inserted card) removed and inaccessible.
> + */
> +void mmc_host_set_removed(struct mmc_host *host)
> +{
> +       if (host->card)
> +               mmc_card_set_removed(host->card);
> +}
> +
> +EXPORT_SYMBOL(mmc_host_set_removed);
> diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
> index 8dfbc62..3f97659f 100644
> --- a/drivers/mmc/host/rtsx_pci_sdmmc.c
> +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
> @@ -1511,6 +1511,9 @@ static void rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
>         pcr->slots[RTSX_SD_CARD].card_event = NULL;
>         mmc = host->mmc;
>
> +       if (pci_dev_is_disconnected(pcr->pci))
> +               mmc_host_set_removed(mmc);
> +
>         cancel_work_sync(&host->work);
>
>         mutex_lock(&host->host_mutex);
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index ba84f02..a240306 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -588,6 +588,7 @@ struct mmc_host {
>  int mmc_add_host(struct mmc_host *);
>  void mmc_remove_host(struct mmc_host *);
>  void mmc_free_host(struct mmc_host *);
> +void mmc_host_set_removed(struct mmc_host *host);
>  void mmc_of_parse_clk_phase(struct device *dev,
>                             struct mmc_clk_phase_map *map);
>  int mmc_of_parse(struct mmc_host *host);
> --
> 2.53.0
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] mmc: rtsx_pci: Cope with hot-removal of MMC host
  2026-09-08 15:38 ` Ulf Hansson
@ 2026-09-08 16:30   ` Lukas Wunner
  0 siblings, 0 replies; 3+ messages in thread
From: Lukas Wunner @ 2026-09-08 16:30 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Ulf Hansson, Ricky Wu, Derek J. Clark, Matthew Schwartz,
	Pierre-Loup A. Griffais, linux-mmc, Christoph Hellwig,
	Keith Busch

On Tue, Sep 08, 2026 at 05:38:29PM +0200, Ulf Hansson wrote:
> On Sat, Aug 15, 2026 at 10:10AM Lukas Wunner <lukas@wunner.de> wrote:
> > Derek reports a lockup on hot-removal of a PCI-attached Realtek RTS525A
> > MMC host if a card is inserted.  He has root-caused it to the block
> > layer being unaware of the hot-removal and waiting indefinitely in
> > sync_filesystem().
> 
> Is this specific for a PCI based mmc host?

It is specific to *removable* mmc hosts.

> Can this be triggered by just removing a removable SD card?

I don't really know.  The reporter witnessed a lockup because the
card reader was removed upon resume from system sleep.  After
some digging it turned out that the lockup occurred in the call
to blk_report_disk_dead() from __del_gendisk():

https://lore.kernel.org/all/anqw0M6cQLEA0J6d@wunner.de/

Clearly, a call to blk_mark_disk_dead() is missing.  That changes
the behavior to avoid writing dirty data to disk if it's gone.

So the issue can be triggered by removing the SD card reader itself
while a card is inserted.  I cannot tell you whether hot-removing
only the card (but not the card reader) also triggers the issue.
I'm just trying to help fix an issue observed by someone else.
I do not have the hardware at my disposal for testing.
I was assuming that the mmc subsystem already has precautions in place
to support hot removal of cards and that only support for hot removal
of the card reader itself is missing.

There are plenty of Thunderbolt or USB-C docks with integrated MMC
card readers on the market, so this seems like an issue a lot of
users may run into.

> > For comparison, the NVMe subsystem copes with hot-removal by setting the
> > controller state to NVME_CTRL_DEAD in nvme_remove(), which in turn leads
> > to blk_mark_disk_dead() being called from nvme_mark_namespaces_dead().
> > That avoids the indefinite wait in sync_filesystem().
> >
> > Adopt this approach:  Detect hot-removal in rtsx_pci_sdmmc_drv_remove()
> > and invoke a new mmc_host_set_removed() helper which in turn invokes
> > mmc_card_set_removed().  Before flushing outstanding requests to the
> > card in mmc_blk_remove_req(), check for its removal and call
> > blk_mark_disk_dead().
> 
> I need more information to understand the problem and whether the NVMe
> approach is really suitable here.
> 
> What do other block subsystems do?

blk_mark_disk_dead() is the API made available by the block layer
to inform it that the disk is hot-removed.  I just followed the example
of the nvme system, which uses that API.

> > Other removable MMC hosts, in particular if attached via PCI or USB,
> > may need to be amended with a similar check for hot-removal.  The
> > present commit seeks to get that process going.
> 
> So it's specific for USB and PCI, why?

Because those buses allow hot-removal of the card reader.

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-08 16:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-15  8:10 [PATCH] mmc: rtsx_pci: Cope with hot-removal of MMC host Lukas Wunner
2026-09-08 15:38 ` Ulf Hansson
2026-09-08 16:30   ` Lukas Wunner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox