diff options
| author | Russell King <rmk@flint.arm.linux.org.uk> | 2004-08-30 19:17:25 +0100 |
|---|---|---|
| committer | Russell King <rmk@flint.arm.linux.org.uk> | 2004-08-30 19:17:25 +0100 |
| commit | af9fe62937a0e10daef53b425ad2447b96ddafde (patch) | |
| tree | 6ffb5cfa94b665acc1dd4f3d87eb3f0400d6589e | |
| parent | 3dc036d2c94ee441f26a7bc6cc1602c29125d166 (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.c | 71 |
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); |
