Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97f8571e authored by Philipp Zabel's avatar Philipp Zabel Committed by Linus Torvalds
Browse files

pxamci: fix byte aligned DMA transfers



The pxa27x DMA controller defaults to 64-bit alignment. This caused
the SCR reads to fail (and, depending on card type, error out) when
card->raw_scr was not aligned on a 8-byte boundary.

For performance reasons all scatter-gather addresses passed to
pxamci_request should be aligned on 8-byte boundaries, but if
this can't be guaranteed, byte aligned DMA transfers in the
have to be enabled in the controller to get correct behaviour.

Signed-off-by: default avatarPhilipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 09ca8adb
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
	unsigned int nob = data->blocks;
	unsigned long long clks;
	unsigned int timeout;
	bool dalgn = 0;
	u32 dcmd;
	int i;

@@ -152,6 +153,9 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
		host->sg_cpu[i].dcmd = dcmd | length;
		if (length & 31 && !(data->flags & MMC_DATA_READ))
			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
		/* Not aligned to 8-byte boundary? */
		if (sg_dma_address(&data->sg[i]) & 0x7)
			dalgn = 1;
		if (data->flags & MMC_DATA_READ) {
			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -165,6 +169,15 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
	wmb();

	/*
	 * The PXA27x DMA controller encounters overhead when working with
	 * unaligned (to 8-byte boundaries) data, so switch on byte alignment
	 * mode only if we have unaligned data.
	 */
	if (dalgn)
		DALGN |= (1 << host->dma);
	else
		DALGN &= (1 << host->dma);
	DDADR(host->dma) = host->sg_dma;
	DCSR(host->dma) = DCSR_RUN;
}