On Mon, Jul 10, 2023 at 07:23:34PM +0200, Jules Maselbas wrote: > When working with 64-bit DMA the DMA addresse is stored in two 32-bit > registers, different from the usual 32-bit one. Copy what is done by > Linux which simple and is also a workaround for some broken controller. > > Note: in case the 64-bit DMA address needs to be read, it must be done > by reading the 32-bit LSB first (SDHCI_ADMA_ADDRESS) and then the MSB > (SDHCI_ADMA_ADDRESS_HI). > > Adapted from Linux commit: > 8<---------------------------------------------------------------------- > commit f6a03cbf43e586211f8ea088148c8ecd3fc4b5be > Author: Mikko Vinni <mmvinni@xxxxxxxxx> > Date: Tue Apr 12 09:36:18 2011 -0400 > > mmc: sdhci: work around broken dma boundary behavior > > Some SD host controllers (noticed on an integrated JMicron SD reader on an > HP Pavilion dv5-1250eo laptop) don't update the dma address register before > signaling a dma interrupt due to a dma boundary. Update the register > manually to the next boundary (by default 512KiB), at which the transfer > stopped. > > As long as each transfer is at most 512KiB in size (guaranteed by a BUG_ON > in sdhci_prepare_data()) and the boundary is kept at the default value, > this fix is needed at most once per transfer. Smaller boundaries are taken > care of by counting the transferred bytes. > > Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=28462 > > Signed-off-by: Mikko Vinni <mmvinni@xxxxxxxxx> > Signed-off-by: Chris Ball <cjb@xxxxxxxxxx> > 8<---------------------------------------------------------------------- > > Signed-off-by: Jules Maselbas <jmaselbas@xxxxxxxxx> > --- > drivers/mci/sdhci.c | 12 +++++++++++- > 1 file changed, 11 insertions(+), 1 deletion(-) > > diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c > index 4aca3af5aa..4c8e73d94d 100644 > --- a/drivers/mci/sdhci.c > +++ b/drivers/mci/sdhci.c > @@ -279,8 +279,18 @@ int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data, > goto out; > } > > + /* > + * We currently don't do anything fancy with DMA > + * boundaries, but as we can't disable the feature > + * we need to at least restart the transfer. > + * > + * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS) > + * should return a valid address to continue from, but as > + * some controllers are faulty, don't trust them. > + */ > if (irqstat & SDHCI_INT_DMA) { > - u32 addr = sdhci_read32(sdhci, SDHCI_DMA_ADDRESS); > + /* Force update to the next DMA block boundary. */ > + dma += sdhci->sdma_boundary; I've modified this to increase the dma addresse instead of aligning the addresse to the next boundary... I don't know why this works in my case, but by reading the SDHCI spec this should really be aligned on a boundary, maybe the behavior is different when v4_mode is enabled. > > /* > * DMA engine has stopped on buffer boundary. Acknowledge > -- > 2.17.1 >