diff options
author | Micky Ching <micky_ching@realsil.com.cn> | 2014-02-17 16:45:48 +0800 |
---|---|---|
committer | Chris Ball <chris@printf.net> | 2014-02-22 13:34:20 -0500 |
commit | c42deffd5b53c9e583d83c7964854ede2f12410d (patch) | |
tree | 9f243972c38e08f15e612a9a13489a6b2db3ddd2 /drivers/mfd | |
parent | abcc6b2943145ae2e17a52632ccab50cd612914c (diff) | |
download | linux-c42deffd5b53c9e583d83c7964854ede2f12410d.tar.gz linux-c42deffd5b53c9e583d83c7964854ede2f12410d.tar.bz2 linux-c42deffd5b53c9e583d83c7964854ede2f12410d.zip |
mmc: rtsx: add support for pre_req and post_req
Add support for non-blocking request, pre_req() runs dma_map_sg() and
post_req() runs dma_unmap_sg(). This patch can increase card read/write
speed, especially for high speed card and slow CPU(for some embedded
platform).
Users can get a great benefit from this patch. if CPU frequency is 800MHz,
SDR104 or DDR50 card read/write speed may increase more than 15%.
test results:
intel i3(800MHz - 2.3GHz), SD card clock 208MHz
performance mode(2.3GHz):
Before:
dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024
67108864 bytes (67 MB) copied, 1.18191 s, 56.8 MB/s
After:
dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024
67108864 bytes (67 MB) copied, 1.09276 s, 61.4 MB/s
powersave mode(800MHz):
Before:
dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024
67108864 bytes (67 MB) copied, 1.29569 s, 51.8 MB/s
After:
dd if=/dev/mmcblk0p1 of=/dev/null bs=64k count=1024
67108864 bytes (67 MB) copied, 1.11218 s, 60.3 MB/s
Signed-off-by: Micky Ching <micky_ching@realsil.com.cn>
Signed-off-by: Chris Ball <chris@printf.net>
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/rtsx_pcr.c | 132 |
1 files changed, 91 insertions, 41 deletions
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 1d15735f9ef9..c9de3d598ea5 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, int num_sg, bool read, int timeout) { struct completion trans_done; - u8 dir; - int err = 0, i, count; + int err = 0, count; long timeleft; unsigned long flags; - struct scatterlist *sg; - enum dma_data_direction dma_dir; - u32 val; - dma_addr_t addr; - unsigned int len; - - dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg); - - /* don't transfer data during abort processing */ - if (pcr->remove_pci) - return -EINVAL; - - if ((sglist == NULL) || (num_sg <= 0)) - return -EINVAL; - if (read) { - dir = DEVICE_TO_HOST; - dma_dir = DMA_FROM_DEVICE; - } else { - dir = HOST_TO_DEVICE; - dma_dir = DMA_TO_DEVICE; - } - - count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read); if (count < 1) { dev_err(&(pcr->pci->dev), "scatterlist map failed\n"); return -EINVAL; } dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count); - val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; - pcr->sgi = 0; - for_each_sg(sglist, sg, count, i) { - addr = sg_dma_address(sg); - len = sg_dma_len(sg); - rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); - } spin_lock_irqsave(&pcr->lock, flags); pcr->done = &trans_done; pcr->trans_result = TRANS_NOT_READY; init_completion(&trans_done); - rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); - rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); spin_unlock_irqrestore(&pcr->lock, flags); + rtsx_pci_dma_transfer(pcr, sglist, count, read); + timeleft = wait_for_completion_interruptible_timeout( &trans_done, msecs_to_jiffies(timeout)); if (timeleft <= 0) { @@ -413,7 +383,7 @@ out: pcr->done = NULL; spin_unlock_irqrestore(&pcr->lock, flags); - dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read); if ((err < 0) && (err != -ENODEV)) rtsx_pci_stop_cmd(pcr); @@ -425,6 +395,73 @@ out: } EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); +int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read) +{ + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (pcr->remove_pci) + return -EINVAL; + + if ((sglist == NULL) || num_sg < 1) + return -EINVAL; + + return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir); +} +EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg); + +int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read) +{ + enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (pcr->remove_pci) + return -EINVAL; + + if (sglist == NULL || num_sg < 1) + return -EINVAL; + + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir); + return num_sg; +} +EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg); + +int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int sg_count, bool read) +{ + struct scatterlist *sg; + dma_addr_t addr; + unsigned int len; + int i; + u32 val; + u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE; + unsigned long flags; + + if (pcr->remove_pci) + return -EINVAL; + + if ((sglist == NULL) || (sg_count < 1)) + return -EINVAL; + + val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; + pcr->sgi = 0; + for_each_sg(sglist, sg, sg_count, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1); + } + + spin_lock_irqsave(&pcr->lock, flags); + + rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer); + int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) { int err; @@ -836,6 +873,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); /* Clear interrupt flag */ rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); + dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg); + if ((int_reg & pcr->bier) == 0) { spin_unlock(&pcr->lock); return IRQ_NONE; @@ -866,17 +905,28 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) } if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { - if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) { + if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) pcr->trans_result = TRANS_RESULT_FAIL; - if (pcr->done) - complete(pcr->done); - } else if (int_reg & TRANS_OK_INT) { + else if (int_reg & TRANS_OK_INT) pcr->trans_result = TRANS_RESULT_OK; - if (pcr->done) - complete(pcr->done); + + if (pcr->done) + complete(pcr->done); + + if (int_reg & SD_EXIST) { + struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD]; + if (slot && slot->done_transfer) + slot->done_transfer(slot->p_dev); + } + + if (int_reg & MS_EXIST) { + struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD]; + if (slot && slot->done_transfer) + slot->done_transfer(slot->p_dev); } } + if (pcr->card_inserted || pcr->card_removed) schedule_delayed_work(&pcr->carddet_work, msecs_to_jiffies(200)); |