Commit 2b76e0cc authored by Matthew Schwartz's avatar Matthew Schwartz Committed by Ulf Hansson
Browse files

mmc: sdhci-pci-gli: fix GL9750 DMA write corruption

The GL9750 SD host controller has intermittent data corruption during
DMA write operations. The GM_BURST register's R_OSRC_Lmt field
(bits 17:16), which limits outstanding DMA read requests from system
memory, is not being cleared during initialization. The Windows driver
sets R_OSRC_Lmt to zero, limiting requests to the smallest unit.

Clear R_OSRC_Lmt to match the Windows driver behavior. This eliminates
write corruption verified with f3write/f3read tests while maintaining
DMA performance.

Cc: stable@vger.kernel.org
Fixes: e51df6ce ("mmc: host: sdhci-pci: Add Genesys Logic GL975x support")
Closes: https://lore.kernel.org/linux-mmc/33d12807-5c72-41ce-8679-57aa11831fad@linux.dev/


Acked-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarMatthew Schwartz <matthew.schwartz@linux.dev>
Reviewed-by: default avatarBen Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 901084c5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@
#define   GLI_9750_MISC_TX1_DLY_VALUE    0x5
#define   SDHCI_GLI_9750_MISC_SSC_OFF    BIT(26)

#define SDHCI_GLI_9750_GM_BURST_SIZE		  0x510
#define   SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT  GENMASK(17, 16)

#define SDHCI_GLI_9750_TUNING_CONTROL	          0x540
#define   SDHCI_GLI_9750_TUNING_CONTROL_EN          BIT(4)
#define   GLI_9750_TUNING_CONTROL_EN_ON             0x1
@@ -345,10 +348,16 @@ static void gli_set_9750(struct sdhci_host *host)
	u32 misc_value;
	u32 parameter_value;
	u32 control_value;
	u32 burst_value;
	u16 ctrl2;

	gl9750_wt_on(host);

	/* clear R_OSRC_Lmt to avoid DMA write corruption */
	burst_value = sdhci_readl(host, SDHCI_GLI_9750_GM_BURST_SIZE);
	burst_value &= ~SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT;
	sdhci_writel(host, burst_value, SDHCI_GLI_9750_GM_BURST_SIZE);

	driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING);
	pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);
	sw_ctrl_value = sdhci_readl(host, SDHCI_GLI_9750_SW_CTRL);