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

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: e51df6ce668a ("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: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Reviewed-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Matthew Schwartz and committed by
Ulf Hansson
2b76e0cc 901084c5

+9
+9
drivers/mmc/host/sdhci-pci-gli.c
··· 68 68 #define GLI_9750_MISC_TX1_DLY_VALUE 0x5 69 69 #define SDHCI_GLI_9750_MISC_SSC_OFF BIT(26) 70 70 71 + #define SDHCI_GLI_9750_GM_BURST_SIZE 0x510 72 + #define SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT GENMASK(17, 16) 73 + 71 74 #define SDHCI_GLI_9750_TUNING_CONTROL 0x540 72 75 #define SDHCI_GLI_9750_TUNING_CONTROL_EN BIT(4) 73 76 #define GLI_9750_TUNING_CONTROL_EN_ON 0x1 ··· 348 345 u32 misc_value; 349 346 u32 parameter_value; 350 347 u32 control_value; 348 + u32 burst_value; 351 349 u16 ctrl2; 352 350 353 351 gl9750_wt_on(host); 352 + 353 + /* clear R_OSRC_Lmt to avoid DMA write corruption */ 354 + burst_value = sdhci_readl(host, SDHCI_GLI_9750_GM_BURST_SIZE); 355 + burst_value &= ~SDHCI_GLI_9750_GM_BURST_SIZE_R_OSRC_LMT; 356 + sdhci_writel(host, burst_value, SDHCI_GLI_9750_GM_BURST_SIZE); 354 357 355 358 driving_value = sdhci_readl(host, SDHCI_GLI_9750_DRIVING); 356 359 pll_value = sdhci_readl(host, SDHCI_GLI_9750_PLL);