mmc: rtsx: fix bug and support nonblocking request
Subsystems (2)
cover mmc: rtsx: fix bug and support nonblocking request
From: Micky Ching <[email protected]>
First we fix the card poweroff bug: the card power is not shutdown when sd/mmc card removed, this will make UHS-card failed to running in high speed mode if we insert the card again.
We offer a concise tuning searching method, it is much easier to read.
At last we add support for nonblocking request, which will improve card read speed at about 10% write speed about 5% normally.
Micky Ching (3):
mmc: rtsx: fix card poweroff bug
mmc: rtsx: modify phase searching method for tuning
mmc: rtsx: add support for pre_req and post_req
drivers/mfd/rtsx_pcr.c | 132 ++++++--- drivers/mmc/host/rtsx_pci_sdmmc.c | 537 ++++++++++++++++++++++++++----------- include/linux/mfd/rtsx_common.h | 1 + include/linux/mfd/rtsx_pci.h | 8 +- 4 files changed, 481 insertions(+), 197 deletions(-)
--
1.7.9.5
PATCH RESEND 1/3 mmc: rtsx: fix card poweroff bug
From: Micky Ching <[email protected]>
If the host driver removed while card in the slot, the host will not power off card power correctly. This bug is produced because host eject flag set before the last mmc_set_ios callback, we should set the eject flag after power off.
--- drivers/mmc/host/rtsx_pci_sdmmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +2 -1
@@ -1328,7 +1328,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) pcr->slots[RTSX_SD_CARD ].p_dev =NULL ; pcr->slots[RTSX_SD_CARD ].card_event =NULL ; mmc = host->mmc; - host->eject = true;mutex_lock (&host->host_mutex);if (host->mrq) {
@@ -1346,6 +1345,8 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)mutex_unlock (&host->host_mutex);mmc_remove_host (mmc); + host->eject = true; +mmc_free_host (mmc); dev_dbg(&(pdev->dev),
Signature · 1 line
1.7.9.5
PATCH RESEND 2/3 mmc: rtsx: modify phase searching method for tuning
In reply to [email protected]From: Micky Ching <[email protected]>
The new phase searching method is more concise and easier to understand.
--- drivers/mmc/host/rtsx_pci_sdmmc.c | 112 +++++++++++-------------------------- include/linux/mfd/rtsx_pci.h | 2 +- 2 files changed, 33 insertions(+), 81 deletions(-)
drivers/mmc/host/rtsx_pci_sdmmc.c +32 -80
@@ -31,16 +31,6 @@#include <linux/mfd/rtsx_pci.h> #include <asm/unaligned.h> -/* SD Tuning Data Structure -* Record continuous timing phase path -*/ -struct timing_phase_path { -int start; -int end; -int mid; -int len; -}; -struct realtek_pci_sdmmc {struct platform_device *pdev;struct rtsx_pcr *pcr;
@@ -511,85 +501,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,return 0 ; } -static u8 sd_search_final_phase (struct realtek_pci_sdmmc *host,u32 phase_map) +static inline u32 test_phase_bit (u32 phase_map,unsigned int bit) { -struct timing_phase_path path[MAX_PHASE +1 ]; -int i, j, cont_path_cnt; -int new_block, max_len, final_path_idx; -u8 final_phase =0xFF ; + bit %=RTSX_PHASE_MAX ; +return phase_map & (1 << bit); +} -/* Parse phase_map, take it as a bit-ring */ - cont_path_cnt =0 ; - new_block =1 ; - j =0 ; -for (i =0 ; i <MAX_PHASE +1 ; i++) { -if (phase_map & (1 << i)) { -if (new_block) { - new_block =0 ; - j = cont_path_cnt++; - path[j].start = i; - path[j].end = i; - }else { - path[j].end = i; - } - }else { - new_block =1 ; -if (cont_path_cnt) { -/* Calculate path length and middle point */ -int idx = cont_path_cnt -1 ; - path[idx].len = - path[idx].end - path[idx].start +1 ; - path[idx].mid = - path[idx].start + path[idx].len /2 ; - } - } - } +static int sd_get_phase_len (u32 phase_map,unsigned int start_bit) +{ +int i; -if (cont_path_cnt ==0 ) { -dev_dbg (sdmmc_dev (host),"No continuous phase path\n" ); - goto finish; - }else { -/* Calculate last continuous path length and middle point */ -int idx = cont_path_cnt -1 ; - path[idx].len = path[idx].end - path[idx].start +1 ; - path[idx].mid = path[idx].start + path[idx].len /2 ; +for (i =0 ; i <RTSX_PHASE_MAX ; i++) { +if (test_phase_bit (phase_map, start_bit + i) ==0 ) +return i; } +return RTSX_PHASE_MAX ; +} + +static u8 sd_search_final_phase (struct realtek_pci_sdmmc *host,u32 phase_map) +{ +int start =0 , len =0 ; +int start_final =0 , len_final =0 ; +u8 final_phase =0xFF ; -/* Connect the first and last continuous paths if they are adjacent */ -if (!path[0 ].start && (path[cont_path_cnt -1 ].end ==MAX_PHASE )) { -/* Using negative index */ - path[0 ].start = path[cont_path_cnt -1 ].start -MAX_PHASE -1 ; - path[0 ].len += path[cont_path_cnt -1 ].len; - path[0 ].mid = path[0 ].start + path[0 ].len /2 ; -/* Convert negative middle point index to positive one */ -if (path[0 ].mid <0 ) - path[0 ].mid +=MAX_PHASE +1 ; - cont_path_cnt--; +if (phase_map ==0 ) { +dev_err (sdmmc_dev (host),"phase error: [map:%x]\n" , phase_map); +return final_phase; } -/* Choose the longest continuous phase path */ - max_len =0 ; - final_phase =0 ; - final_path_idx =0 ; -for (i =0 ; i < cont_path_cnt; i++) { -if (path[i].len > max_len) { - max_len = path[i].len; - final_phase = (u8 )path[i].mid; - final_path_idx = i; +while (start <RTSX_PHASE_MAX ) { + len =sd_get_phase_len (phase_map, start); +if (len_final < len) { + start_final = start; + len_final = len; } - -dev_dbg (sdmmc_dev (host),"path[%d].start = %d\n" , - i, path[i].start); -dev_dbg (sdmmc_dev (host),"path[%d].end = %d\n" , - i, path[i].end); -dev_dbg (sdmmc_dev (host),"path[%d].len = %d\n" , - i, path[i].len); -dev_dbg (sdmmc_dev (host),"path[%d].mid = %d\n" , - i, path[i].mid); + start += len ? len :1 ; } -finish: -dev_dbg (sdmmc_dev (host),"Final chosen phase: %d\n" , final_phase); + final_phase = (start_final + len_final /2 ) %RTSX_PHASE_MAX ; +dev_dbg (sdmmc_dev (host),"phase: [map:%x] [maxlen:%d] [final:%d]\n" , + phase_map, len_final, final_phase); +return final_phase; }
@@ -635,7 +587,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host,int err, i;u32 raw_phase_map =0 ; -for (i =MAX_PHASE ; i >=0 ; i--) { +for (i =0 ; i <RTSX_PHASE_MAX ; i++) { err =sd_tuning_rx_cmd (host, opcode, (u8 )i);if (err ==0 ) raw_phase_map |=1 << i;
include/linux/mfd/rtsx_pci.h +1 -1
@@ -144,7 +144,7 @@#define HOST_TO_DEVICE 0#define DEVICE_TO_HOST 1 -#define MAX_PHASE 31 +#define RTSX_PHASE_MAX 32#define RX_TUNING_CNT 3/* SG descriptor */
Signature · 1 line
1.7.9.5
PATCH RESEND 3/3 mmc: rtsx: add support for pre_req and post_req
In reply to [email protected]From: Micky Ching <[email protected]>
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
--- drivers/mfd/rtsx_pcr.c | 132 ++++++++---- drivers/mmc/host/rtsx_pci_sdmmc.c | 426 ++++++++++++++++++++++++++++++------- include/linux/mfd/rtsx_common.h | 1 + include/linux/mfd/rtsx_pci.h | 6 + 4 files changed, 448 insertions(+), 117 deletions(-)
drivers/mfd/rtsx_pcr.c +91 -41
@@ -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 ));
drivers/mmc/host/rtsx_pci_sdmmc.c +350 -76
619 lines not on this page · raw message
include/linux/mfd/rtsx_common.h +1 -0
@@ -45,6 +45,7 @@ struct platform_device;struct rtsx_slot {struct platform_device *p_dev;void (*card_event)(struct platform_device *p_dev); +void (*done_transfer)(struct platform_device *p_dev); };#endif
include/linux/mfd/rtsx_pci.h +6 -0
@@ -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_transfer_data (struct rtsx_pcr *pcr,struct scatterlist *sglist,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_write_ppbuf (struct rtsx_pcr *pcr,u8 *buf,int buf_len);int rtsx_pci_card_pull_ctl_enable (struct rtsx_pcr *pcr,int card);
Signature · 1 line
1.7.9.5
Hi Micky,
Quoted 11 lines · On Mon, Feb 17, 2014 at 10:00:54AM +0800, [email protected] wrote:
From: Micky Ching <[email protected]>
First we fix the card poweroff bug: the card power is not shutdown when sd/mmc card removed, this will make UHS-card failed to running in high speed mode if we insert the card again.
We offer a concise tuning searching method, it is much easier to read.
At last we add support for nonblocking request, which will improve card read speed at about 10% write speed about 5% normally.
Quoted 6 lines
Micky Ching (3):
mmc: rtsx: fix card poweroff bug
mmc: rtsx: modify phase searching method for tuning
mmc: rtsx: add support forpre_reqandpost_reqdrivers/mfd/rtsx_pcr.c | 132 ++++++---
Please add Lee Jones (cc'ed) for MFD.
Cheers,
Samuel.
Signature · 2 lines
Intel Open Source Technology Centre http://oss.intel.com/