summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@flint.arm.linux.org.uk>2004-08-30 19:17:25 +0100
committerRussell King <rmk@flint.arm.linux.org.uk>2004-08-30 19:17:25 +0100
commitaf9fe62937a0e10daef53b425ad2447b96ddafde (patch)
tree6ffb5cfa94b665acc1dd4f3d87eb3f0400d6589e
parent3dc036d2c94ee441f26a7bc6cc1602c29125d166 (diff)
[MMC] MMCI: Add SG support to PIO data transfers
This allows us to transfer a whole request for multiple pages in one transaction with the MMC card, resulting in higher overall throughput.
-rw-r--r--drivers/mmc/mmci.c71
1 files changed, 66 insertions, 5 deletions
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 559cea6eaa85..70cc162af9ef 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -197,6 +197,7 @@ static int mmci_pio_read(struct mmci_host *host, struct request *req, u32 status
do {
unsigned long flags;
+ unsigned int bio_remain;
char *buffer;
/*
@@ -208,23 +209,44 @@ static int mmci_pio_read(struct mmci_host *host, struct request *req, u32 status
/*
* Map the BIO buffer.
*/
- buffer = bio_kmap_irq(req->bio, &flags);
+ buffer = bio_kmap_irq(req->cbio, &flags);
+ bio_remain = (req->current_nr_sectors << 9) - host->offset;
do {
int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+ if (count > bio_remain)
+ count = bio_remain;
+
if (count > 0) {
ret = 1;
readsl(base + MMCIFIFO, buffer + host->offset, count >> 2);
host->offset += count;
host->size -= count;
+ bio_remain -= count;
+ if (bio_remain == 0)
+ goto next_bio;
}
status = readl(base + MMCISTATUS);
- } while (status & MCI_RXDATAAVLBL && host->size);
+ } while (status & MCI_RXDATAAVLBL);
bio_kunmap_irq(buffer, &flags);
break;
+
+ next_bio:
+ bio_kunmap_irq(buffer, &flags);
+
+ /*
+ * Ok, we've completed that BIO, move on to next
+ * BIO in the chain. Note: this doesn't actually
+ * complete the BIO!
+ */
+ if (!process_that_request_first(req, req->current_nr_sectors))
+ break;
+
+ host->offset = 0;
+ status = readl(base + MMCISTATUS);
} while (1);
return ret;
@@ -237,6 +259,7 @@ static int mmci_pio_write(struct mmci_host *host, struct request *req, u32 statu
do {
unsigned long flags;
+ unsigned int bio_remain;
char *buffer;
/*
@@ -250,26 +273,45 @@ static int mmci_pio_write(struct mmci_host *host, struct request *req, u32 statu
/*
* Map the BIO buffer.
*/
- buffer = bio_kmap_irq(req->bio, &flags);
+ buffer = bio_kmap_irq(req->cbio, &flags);
+ bio_remain = (req->current_nr_sectors << 9) - host->offset;
do {
unsigned int count, maxcnt;
maxcnt = status & MCI_TXFIFOEMPTY ?
MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
- count = min(host->size, maxcnt);
+ count = min(bio_remain, maxcnt);
writesl(base + MMCIFIFO, buffer + host->offset, count >> 2);
host->offset += count;
host->size -= count;
+ bio_remain -= count;
ret = 1;
+ if (bio_remain == 0)
+ goto next_bio;
+
status = readl(base + MMCISTATUS);
- } while (status & MCI_TXFIFOHALFEMPTY && host->size);
+ } while (status & MCI_TXFIFOHALFEMPTY);
bio_kunmap_irq(buffer, &flags);
break;
+
+ next_bio:
+ bio_kunmap_irq(buffer, &flags);
+
+ /*
+ * Ok, we've completed that BIO, move on to next
+ * BIO in the chain. Note: this doesn't actually
+ * complete the BIO!
+ */
+ if (!process_that_request_first(req, req->current_nr_sectors))
+ break;
+
+ host->offset = 0;
+ status = readl(base + MMCISTATUS);
} while (1);
return ret;
@@ -483,6 +525,25 @@ static int mmci_probe(struct amba_device *dev, void *id)
mmc->f_max = min(host->mclk, fmax);
mmc->ocr_avail = plat->ocr_mask;
+ /*
+ * We can do SGIO
+ */
+ mmc->max_hw_segs = 16;
+ mmc->max_phys_segs = 16;
+
+ /*
+ * Since we only have a 16-bit data length register, we must
+ * ensure that we don't exceed 2^16-1 bytes in a single request.
+ * Choose 64 (512-byte) sectors as the limit.
+ */
+ mmc->max_sectors = 64;
+
+ /*
+ * Set the maximum segment size. Since we aren't doing DMA
+ * (yet) we are only limited by the data length register.
+ */
+ mmc->max_seg_size = mmc->max_sectors << 9;
+
spin_lock_init(&host->lock);
writel(0, host->base + MMCIMASK0);