hack not works
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index ca01b7d..23d9232 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -29,7 +29,7 @@
#define DRIVER_NAME "mvsdio"
static int maxfreq;
-static int nodma;
+static int nodma=1;
struct mvsd_host {
void __iomem *base;
@@ -38,8 +38,9 @@ struct mvsd_host {
unsigned int xfer_mode;
unsigned int intr_en;
unsigned int ctrl;
+ bool use_pio;
+ struct sg_mapping_iter sg_miter;
unsigned int pio_size;
- void *pio_ptr;
unsigned int sg_frags;
unsigned int ns_per_clk;
unsigned int clock;
@@ -114,11 +115,18 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
* data when the buffer is not aligned on a 64 byte
* boundary.
*/
+ unsigned int miter_flags = SG_MITER_ATOMIC; /* Used from IRQ */
+
+ if (data->flags & MMC_DATA_READ)
+ miter_flags |= SG_MITER_TO_SG;
+ else
+ miter_flags |= SG_MITER_FROM_SG;
+
host->pio_size = data->blocks * data->blksz;
- host->pio_ptr = sg_virt(data->sg);
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, miter_flags);
if (!nodma)
- dev_dbg(host->dev, "fallback to PIO for data at 0x%p size %d\n",
- host->pio_ptr, host->pio_size);
+ dev_dbg(host->dev, "fallback to PIO for data\n");
+ host->use_pio = true;
return 1;
} else {
dma_addr_t phys_addr;
@@ -129,6 +137,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
phys_addr = sg_dma_address(data->sg);
mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff);
mvsd_write(MVSD_SYS_ADDR_HI, (u32)phys_addr >> 16);
+ host->use_pio = false;
return 0;
}
}
@@ -288,8 +297,8 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
{
void __iomem *iobase = host->base;
- if (host->pio_ptr) {
- host->pio_ptr = NULL;
+ if (host->use_pio) {
+ sg_miter_stop(&host->sg_miter);
host->pio_size = 0;
} else {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags,
@@ -341,6 +350,128 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
return err_status;
}
+static int mvsd_pio(struct mvsd_host *host, u32 *intr_status)
+{
+ struct sg_mapping_iter *sgm = &host->sg_miter;
+ void __iomem *iobase = host->base;
+ unsigned int consumed = 0;
+ int irq_handled = 0;
+ u32 irs = *intr_status;
+ u16 *p;
+ int s; /* Remaining in current segment */
+
+ /*
+ * As we set sgm->consumed this always gives a valid buffer
+ * position.
+ */
+ if (!sg_miter_next(sgm)) {
+ /* This should not happen */
+ if (host->pio_size)
+ dev_err(host->dev, "ran out of scatter segments\n");
+ spin_unlock(&host->lock);
+ host->intr_en &=
+ ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W |
+ MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);
+ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
+ return 1;
+ }
+
+ p = sgm->addr;
+ s = sgm->length;
+ if (s > host->pio_size)
+ s = host->pio_size;
+
+ /* PIO handling, if needed. Messy business... */
+ if ((irs & host->intr_en &
+ (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) {
+ while (s >= 32 && (irs & MVSD_NOR_RX_FIFO_8W)) {
+ readsw(iobase + MVSD_FIFO, p, 16);
+ p += 16;
+ s -= 32;
+ consumed += 32;
+ irs = mvsd_read(MVSD_NOR_INTR_STATUS);
+ }
+ /*
+ * Normally we'd use < 32 here, but the RX_FIFO_8W bit
+ * doesn't appear to assert when there is exactly 32 bytes
+ * (8 words) left to fetch in a transfer.
+ */
+ if (s <= 32) {
+ while (s >= 4 && (irs & MVSD_NOR_RX_READY)) {
+ put_unaligned(mvsd_read(MVSD_FIFO), p++);
+ put_unaligned(mvsd_read(MVSD_FIFO), p++);
+ s -= 4;
+ consumed += 4;
+ irs = mvsd_read(MVSD_NOR_INTR_STATUS);
+ }
+ if (s && s < 4 && (irs & MVSD_NOR_RX_READY)) {
+ u16 val[2] = {0, 0};
+ val[0] = mvsd_read(MVSD_FIFO);
+ val[1] = mvsd_read(MVSD_FIFO);
+ memcpy(p, ((void *)&val) + 4 - s, s);
+ consumed += s;
+ s = 0;
+ irs = mvsd_read(MVSD_NOR_INTR_STATUS);
+ }
+ /* PIO transfer done */
+ host->pio_size -= consumed;
+ sgm->consumed = consumed;
+ if (host->pio_size == 0) {
+ host->intr_en &=
+ ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W);
+ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
+ } else if (host->intr_en & MVSD_NOR_RX_FIFO_8W) {
+ host->intr_en &= ~MVSD_NOR_RX_FIFO_8W;
+ host->intr_en |= MVSD_NOR_RX_READY;
+ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
+ }
+ }
+ dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
+ s, irs, mvsd_read(MVSD_HW_STATE));
+ irq_handled = 1;
+ } else if ((irs & host->intr_en &
+ (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) {
+ /*
+ * The TX_FIFO_8W bit is unreliable. When set, bursting
+ * 16 halfwords all at once in the FIFO drops data. Actually
+ * TX_AVAIL does go off after only one word is pushed even if
+ * TX_FIFO_8W remains set.
+ */
+ while (s >= 4 && (irs & MVSD_NOR_TX_AVAIL)) {
+ mvsd_write(MVSD_FIFO, get_unaligned(p++));
+ mvsd_write(MVSD_FIFO, get_unaligned(p++));
+ s -= 4;
+ consumed += 4;
+ irs = mvsd_read(MVSD_NOR_INTR_STATUS);
+ }
+ if (s < 4) {
+ if (s && (irs & MVSD_NOR_TX_AVAIL)) {
+ u16 val[2] = {0, 0};
+ memcpy(((void *)&val) + 4 - s, p, s);
+ mvsd_write(MVSD_FIFO, val[0]);
+ mvsd_write(MVSD_FIFO, val[1]);
+ consumed += s;
+ s = 0;
+ irs = mvsd_read(MVSD_NOR_INTR_STATUS);
+ }
+ /* PIO transfer done */
+ host->pio_size -= consumed;
+ sgm->consumed = consumed;
+ if (host->pio_size == 0) {
+ host->intr_en &=
+ ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);
+ mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
+ }
+ }
+ dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
+ s, irs, mvsd_read(MVSD_HW_STATE));
+ irq_handled = 1;
+ }
+
+ *intr_status = irs;
+ return irq_handled;
+}
+
static irqreturn_t mvsd_irq(int irq, void *dev)
{
struct mvsd_host *host = dev;
@@ -369,90 +500,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
spin_lock(&host->lock);
- /* PIO handling, if needed. Messy business... */
- if (host->pio_size &&
- (intr_status & host->intr_en &
- (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) {
- u16 *p = host->pio_ptr;
- int s = host->pio_size;
- while (s >= 32 && (intr_status & MVSD_NOR_RX_FIFO_8W)) {
- readsw(iobase + MVSD_FIFO, p, 16);
- p += 16;
- s -= 32;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- /*
- * Normally we'd use < 32 here, but the RX_FIFO_8W bit
- * doesn't appear to assert when there is exactly 32 bytes
- * (8 words) left to fetch in a transfer.
- */
- if (s <= 32) {
- while (s >= 4 && (intr_status & MVSD_NOR_RX_READY)) {
- put_unaligned(mvsd_read(MVSD_FIFO), p++);
- put_unaligned(mvsd_read(MVSD_FIFO), p++);
- s -= 4;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s && s < 4 && (intr_status & MVSD_NOR_RX_READY)) {
- u16 val[2] = {0, 0};
- val[0] = mvsd_read(MVSD_FIFO);
- val[1] = mvsd_read(MVSD_FIFO);
- memcpy(p, ((void *)&val) + 4 - s, s);
- s = 0;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s == 0) {
- host->intr_en &=
- ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W);
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- } else if (host->intr_en & MVSD_NOR_RX_FIFO_8W) {
- host->intr_en &= ~MVSD_NOR_RX_FIFO_8W;
- host->intr_en |= MVSD_NOR_RX_READY;
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- }
- }
- dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
- s, intr_status, mvsd_read(MVSD_HW_STATE));
- host->pio_ptr = p;
- host->pio_size = s;
- irq_handled = 1;
- } else if (host->pio_size &&
- (intr_status & host->intr_en &
- (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) {
- u16 *p = host->pio_ptr;
- int s = host->pio_size;
- /*
- * The TX_FIFO_8W bit is unreliable. When set, bursting
- * 16 halfwords all at once in the FIFO drops data. Actually
- * TX_AVAIL does go off after only one word is pushed even if
- * TX_FIFO_8W remains set.
- */
- while (s >= 4 && (intr_status & MVSD_NOR_TX_AVAIL)) {
- mvsd_write(MVSD_FIFO, get_unaligned(p++));
- mvsd_write(MVSD_FIFO, get_unaligned(p++));
- s -= 4;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s < 4) {
- if (s && (intr_status & MVSD_NOR_TX_AVAIL)) {
- u16 val[2] = {0, 0};
- memcpy(((void *)&val) + 4 - s, p, s);
- mvsd_write(MVSD_FIFO, val[0]);
- mvsd_write(MVSD_FIFO, val[1]);
- s = 0;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s == 0) {
- host->intr_en &=
- ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- }
- }
- dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
- s, intr_status, mvsd_read(MVSD_HW_STATE));
- host->pio_ptr = p;
- host->pio_size = s;
- irq_handled = 1;
+ if (host->use_pio) {
+ irq_handled = mvsd_pio(host, &intr_status);
}
mvsd_write(MVSD_NOR_INTR_STATUS, intr_status);