summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/rtsx_pcr.c
diff options
context:
space:
mode:
authorMicky Ching <micky_ching@realsil.com.cn>2014-02-17 09:45:48 +0100
committerChris Ball <chris@printf.net>2014-02-22 19:34:20 +0100
commitc42deffd5b53c9e583d83c7964854ede2f12410d (patch)
tree9f243972c38e08f15e612a9a13489a6b2db3ddd2 /drivers/mfd/rtsx_pcr.c
parentmmc: rtsx: modify phase searching method for tuning (diff)
downloadlinux-c42deffd5b53c9e583d83c7964854ede2f12410d.tar.xz
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/rtsx_pcr.c')
-rw-r--r--drivers/mfd/rtsx_pcr.c132
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));