Commit c42deffd authored by Micky Ching's avatar Micky Ching Committed by Chris Ball

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: default avatarMicky Ching <micky_ching@realsil.com.cn>
Signed-off-by: default avatarChris Ball <chris@printf.net>
parent abcc6b29
...@@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, ...@@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read, int timeout) int num_sg, bool read, int timeout)
{ {
struct completion trans_done; struct completion trans_done;
u8 dir; int err = 0, count;
int err = 0, i, count;
long timeleft; long timeleft;
unsigned long flags; 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) { count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, 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);
if (count < 1) { if (count < 1) {
dev_err(&(pcr->pci->dev), "scatterlist map failed\n"); dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
return -EINVAL; return -EINVAL;
} }
dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count); 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); spin_lock_irqsave(&pcr->lock, flags);
pcr->done = &trans_done; pcr->done = &trans_done;
pcr->trans_result = TRANS_NOT_READY; pcr->trans_result = TRANS_NOT_READY;
init_completion(&trans_done); 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); spin_unlock_irqrestore(&pcr->lock, flags);
rtsx_pci_dma_transfer(pcr, sglist, count, read);
timeleft = wait_for_completion_interruptible_timeout( timeleft = wait_for_completion_interruptible_timeout(
&trans_done, msecs_to_jiffies(timeout)); &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) { if (timeleft <= 0) {
...@@ -413,7 +383,7 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, ...@@ -413,7 +383,7 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
pcr->done = NULL; pcr->done = NULL;
spin_unlock_irqrestore(&pcr->lock, flags); 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)) if ((err < 0) && (err != -ENODEV))
rtsx_pci_stop_cmd(pcr); rtsx_pci_stop_cmd(pcr);
...@@ -425,6 +395,73 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, ...@@ -425,6 +395,73 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
} }
EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); 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 rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
{ {
int err; int err;
...@@ -836,6 +873,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) ...@@ -836,6 +873,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
/* Clear interrupt flag */ /* Clear interrupt flag */
rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); 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) { if ((int_reg & pcr->bier) == 0) {
spin_unlock(&pcr->lock); spin_unlock(&pcr->lock);
return IRQ_NONE; return IRQ_NONE;
...@@ -866,16 +905,27 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) ...@@ -866,16 +905,27 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
} }
if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { 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; pcr->trans_result = TRANS_RESULT_FAIL;
if (pcr->done) else if (int_reg & TRANS_OK_INT)
complete(pcr->done);
} else if (int_reg & TRANS_OK_INT) {
pcr->trans_result = TRANS_RESULT_OK; pcr->trans_result = TRANS_RESULT_OK;
if (pcr->done) if (pcr->done)
complete(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) if (pcr->card_inserted || pcr->card_removed)
schedule_delayed_work(&pcr->carddet_work, schedule_delayed_work(&pcr->carddet_work,
......
This diff is collapsed.
...@@ -45,6 +45,7 @@ struct platform_device; ...@@ -45,6 +45,7 @@ struct platform_device;
struct rtsx_slot { struct rtsx_slot {
struct platform_device *p_dev; struct platform_device *p_dev;
void (*card_event)(struct platform_device *p_dev); void (*card_event)(struct platform_device *p_dev);
void (*done_transfer)(struct platform_device *p_dev);
}; };
#endif #endif
...@@ -943,6 +943,12 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr); ...@@ -943,6 +943,12 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout); int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read, int timeout); int num_sg, bool read, int timeout);
int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read);
int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int num_sg, bool read);
int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
int sg_count, bool read);
int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len); int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card); int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment