From 41e93ebc83bf91060a9d4a98418037698fb7b241 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Wed, 8 Jan 2025 15:09:53 +0000
Subject: [PATCH] mmc: sd: filter card CQ support based on an allow-list

We have found that many SD cards in the field, even of the same make and
model, have latent bugs in their CQ implementation. Some product lines
have fewer bugs with newer manufacture dates, but this is not a
guarantee that a particular card is at a particular firmware revision
level.

Many of these bugs lead to card hangs or data corruption. Add a quirk to
mark a card as having a tested, working CQ implementation and ignore the
capability if absent.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
 drivers/mmc/core/card.h  | 5 +++++
 drivers/mmc/core/sd.c    | 4 ++++
 include/linux/mmc/card.h | 1 +
 3 files changed, 10 insertions(+)

--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -301,4 +301,9 @@ static inline int mmc_card_no_uhs_ddr50_
 	return c->quirks & MMC_QUIRK_NO_UHS_DDR50_TUNING;
 }
 
+static inline int mmc_card_working_sd_cq(const struct mmc_card *c)
+{
+	return c->quirks & MMC_QUIRK_WORKING_SD_CQ;
+}
+
 #endif
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1517,6 +1517,10 @@ cont:
 			goto free_card;
 	}
 
+	/* Disallow command queueing on unvetted cards */
+	if (!mmc_card_working_sd_cq(card))
+		card->ext_csd.cmdq_support = false;
+
 	/* Enable command queueing if supported */
 	if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
 		/*
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -296,6 +296,7 @@ struct mmc_card {
 #define MMC_QUIRK_BROKEN_CACHE_FLUSH	(1<<16)	/* Don't flush cache until the write has occurred */
 #define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY	(1<<17) /* Disable broken SD poweroff notify support */
 #define MMC_QUIRK_NO_UHS_DDR50_TUNING	(1<<18) /* Disable DDR50 tuning */
+#define MMC_QUIRK_WORKING_SD_CQ	(1<<30)		/* SD card has known-good CQ implementation */
 #define MMC_QUIRK_ERASE_BROKEN	(1<<31)		/* Skip erase */
 
 	bool			written_flag;	/* Indicates eMMC has been written since power on */
