rendered paste bodydiff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.cindex a8e18fe..5bbae05 100644--- a/drivers/mmc/host/pxamci.c+++ b/drivers/mmc/host/pxamci.c@@ -36,6 +36,10 @@ #include "pxamci.h" +/* FIXME: For debugging purposes */+#undef cpu_is_pxa25x+#define cpu_is_pxa25x cpu_is_pxa27x+ #define DRIVER_NAME "pxa2xx-mci" #define NR_SG 1@@ -67,6 +71,10 @@ struct pxamci_host { unsigned int dma_dir; unsigned int dma_drcmrrx; unsigned int dma_drcmrtx;++ dma_addr_t bounce_dma;+ void *bounce_cpu;+ unsigned int offset; }; static void pxamci_stop_clock(struct pxamci_host *host)@@ -116,7 +124,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) unsigned int timeout; bool dalgn = 0; u32 dcmd;- int i;+ int i, j; host->data = data; @@ -148,22 +156,56 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir); - for (i = 0; i < host->dma_len; i++) {+ for (i = 0, j = 0; i < host->dma_len; i++, j++) { unsigned int length = sg_dma_len(&data->sg[i]);- host->sg_cpu[i].dcmd = dcmd | length;- if (length & 31 && !(data->flags & MMC_DATA_READ))- host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;+ unsigned int addr = sg_dma_address(&data->sg[i]);+ unsigned int offset = addr & 7; /* Not aligned to 8-byte boundary? */- if (sg_dma_address(&data->sg[i]) & 0x7)- dalgn = 1;+ if (offset) {+ if (cpu_is_pxa21x() || cpu_is_pxa25x()) {+ /*+ * PXA25x doesn't support unaligned DMA+ * at all, use a bounce buffer once for+ * up to 7 unaligned bytes.+ */+ BUG_ON(host->offset != 0);+ offset = (8 - offset) & 7;+ host->sg_cpu[j].dcmd = dcmd | offset;+ if (length & 31 && !(data->flags & MMC_DATA_READ))+ host->sg_cpu[j].dcmd |= DCMD_ENDIRQEN;+ if (data->flags & MMC_DATA_READ) {+ host->sg_cpu[j].dsadr =+ host->res->start + MMC_RXFIFO;+ host->sg_cpu[j].dtadr =+ host->bounce_dma;+ } else {+ memcpy(host->bounce_cpu, X, offset);+ host->sg_cpu[j].dsadr =+ host->bounce_dma;+ host->sg_cpu[j].dtadr =+ host->res->start + MMC_TXFIFO;+ }+ host->offset = offset;+ host->dma_len++;+ length -= offset;+ addr += offset;+ j++;+ } else {+ /* PXA27x, PXA3xx can handle unaligned DMA */+ dalgn = 1;+ }+ }+ host->sg_cpu[j].dcmd = dcmd | length;+ if (length & 31 && !(data->flags & MMC_DATA_READ))+ host->sg_cpu[j].dcmd |= DCMD_ENDIRQEN; 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]);+ host->sg_cpu[j].dsadr = host->res->start + MMC_RXFIFO;+ host->sg_cpu[j].dtadr = addr; } else {- host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);- host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;+ host->sg_cpu[j].dsadr = addr;+ host->sg_cpu[j].dtadr = host->res->start + MMC_TXFIFO; }- host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *+ host->sg_cpu[j].ddadr = host->sg_dma + (j + 1) * sizeof(struct pxa_dma_desc); } host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;@@ -174,10 +216,12 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) * 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);+ if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {+ if (dalgn)+ DALGN |= (1 << host->dma);+ else+ DALGN &= ~(1 << host->dma);+ } DDADR(host->dma) = host->sg_dma; DCSR(host->dma) = DCSR_RUN; }@@ -281,6 +325,12 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) if (!data) return 0; + if ((cpu_is_pxa21x() || cpu_is_pxa25x())+ && host->offset && data->flags & MMC_DATA_READ) {+ memcpy(XX, host->bounce_cpu, host->offset);+ host->offset = 0;+ }+ DCSR(host->dma) = 0; dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, host->dma_dir);@@ -562,11 +612,20 @@ static int pxamci_probe(struct platform_device *pdev) MMC_CAP_SD_HIGHSPEED; } - host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);+ host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,+ &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { ret = -ENOMEM; goto out; }+ if (cpu_is_pxa25x()) {+ host->bounce = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,+ &host->aligned, GFP_KERNEL);+ if (!host->bounce) {+ ret = -ENOMEM;+ goto out;+ }+ } spin_lock_init(&host->lock); host->res = r;@@ -629,7 +688,11 @@ static int pxamci_probe(struct platform_device *pdev) if (host->base) iounmap(host->base); if (host->sg_cpu)- dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);+ dma_free_coherent(&pdev->dev, PAGE_SIZE,+ host->sg_cpu, host->sg_dma);+ if (cpu_is_pxa25x() && host->bounce_cpu)+ dma_free_coherent(&pdev->dev, PAGE_SIZE,+ host->bounce_cpu, host->bounce_dma); if (host->clk) clk_put(host->clk); }@@ -665,6 +728,9 @@ static int pxamci_remove(struct platform_device *pdev) pxa_free_dma(host->dma); iounmap(host->base); dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);+ if (cpu_is_pxa25x())+ dma_free_coherent(&pdev->dev, PAGE_SIZE,+ host->bounce_cpu, host->bounce_dma); clk_put(host->clk);