History

mmc: alcor: work with multiple-entry sglists

DMA on this hardware is limited to dealing with a 4096 bytes at a time. Previously, the driver was set up accordingly to request single-page DMA buffers, however that had the effect of generating a large number of small MMC requests for data I/O. Improve the driver to accept multi-entry scatter-gather lists. The size of each entry is already capped to 4096 bytes (AU6601_MAX_DMA_BLOCK_SIZE), matching the hardware requirements. Existing driver code already iterates through remaining sglist entries after each DMA transfer is complete. Also add some comments to help clarify the situation, and clear up some of the confusion I had regarding DMA vs PIO. Testing with dd, this increases write performance from 2mb/sec to 10mb/sec, and increases read performance from 4mb/sec to 14mb/sec.

Daniel Drake committed 7 years ago

Commit c671b6d1 parent f19337d2 files · +37 −19Browse files

Unified · Split

2 files
  1. drivers/mmc/host/alcor.c +36 −18
  2. include/linux/alcor_pci.h +1 −1
drivers/mmc/host/alcor.c+36−18
@@ -117,6 +117,9 @@ static void alcor_reset(struct alcor_sdmmc_host *host, u8 val) · 116 unmodified lines
117 dev_err(host->dev, "%s: timeout\n", __func__);117 dev_err(host->dev, "%s: timeout\n", __func__);
118}118}
119 119
120/*
121 * Perform DMA I/O of a single page.
122 */
120static void alcor_data_set_dma(struct alcor_sdmmc_host *host)123static void alcor_data_set_dma(struct alcor_sdmmc_host *host)
121{124{
122 struct alcor_pci_priv *priv = host->alcor_pci;125 struct alcor_pci_priv *priv = host->alcor_pci;
@@ -153,12 +156,26 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host) · 30 unmodified lines
153 ctrl |= AU6601_DATA_WRITE;156 ctrl |= AU6601_DATA_WRITE;
154 157
155 if (data->host_cookie == COOKIE_MAPPED) {158 if (data->host_cookie == COOKIE_MAPPED) {
159 /*
160 * For DMA transfers, this function is called just once,
161 * at the start of the operation. The hardware can only
162 * perform DMA I/O on a single page at a time, so here
163 * we kick off the transfer with the first page, and expect
164 * subsequent pages to be transferred upon IRQ events
165 * indicating that the single-page DMA was completed.
166 */
156 alcor_data_set_dma(host);167 alcor_data_set_dma(host);
157 ctrl |= AU6601_DATA_DMA_MODE;168 ctrl |= AU6601_DATA_DMA_MODE;
158 host->dma_on = 1;169 host->dma_on = 1;
159 alcor_write32(priv, data->sg_count * 0x1000,170 alcor_write32(priv, data->sg_count * 0x1000,
160 AU6601_REG_BLOCK_SIZE);171 AU6601_REG_BLOCK_SIZE);
161 } else {172 } else {
173 /*
174 * For PIO transfers, we break down each operation
175 * into several sector-sized transfers. When one sector has
176 * complete, the IRQ handler will call this function again
177 * to kick off the transfer of the next sector.
178 */
162 alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE);179 alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE);
163 }180 }
164 181
@@ -776,8 +793,12 @@ static void alcor_pre_req(struct mmc_host *mmc, · 611 unmodified lines
776 return;793 return;
777 /*794 /*
778 * We don't do DMA on "complex" transfers, i.e. with795 * We don't do DMA on "complex" transfers, i.e. with
779 * non-word-aligned buffers or lengths. Also, we don't bother796 * non-word-aligned buffers or lengths. A future improvement
780 * with all the DMA setup overhead for short transfers.797 * could be made to use temporary DMA bounce-buffers when these
798 * requirements are not met.
799 *
800 * Also, we don't bother with all the DMA setup overhead for
801 * short transfers.
781 */802 */
782 if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE)803 if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE)
783 return;804 return;
@@ -788,6 +809,8 @@ static void alcor_pre_req(struct mmc_host *mmc, · 4 unmodified lines
788 for_each_sg(data->sg, sg, data->sg_len, i) {809 for_each_sg(data->sg, sg, data->sg_len, i) {
789 if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE)810 if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE)
790 return;811 return;
812 if (sg->offset != 0)
813 return;
791 }814 }
792 815
793 /* This data might be unmapped at this time */816 /* This data might be unmapped at this time */
@@ -1038,26 +1061,21 @@ static void alcor_init_mmc(struct alcor_sdmmc_host *host) · 244 unmodified lines
1038 mmc->ops = &alcor_sdc_ops;1061 mmc->ops = &alcor_sdc_ops;
1039 1062
1040 /* The hardware does DMA data transfer of 4096 bytes to/from a single1063 /* The hardware does DMA data transfer of 4096 bytes to/from a single
1041 * buffer address. Scatterlists are not supported, but upon DMA1064 * buffer address. Scatterlists are not supported at the hardware
1042 * completion (signalled via IRQ), the original vendor driver does1065 * level, however we can work with them at the driver level,
1043 * then immediately set up another DMA transfer of the next 40961066 * provided that each segment is exactly 4096 bytes in size.
1044 * bytes.1067 * Upon DMA completion of a single segment (signalled via IRQ), we
1045 *1068 * immediately proceed to transfer the next segment from the
1046 * This means that we need to handle the I/O in 4096 byte chunks.1069 * scatterlist.
1047 * Lacking a way to limit the sglist entries to 4096 bytes, we instead
1048 * impose that only one segment is provided, with maximum size 4096,
1049 * which also happens to be the minimum size. This means that the
1050 * single-entry sglist handled by this driver can be handed directly
1051 * to the hardware, nice and simple.
1052 *1070 *
1053 * Unfortunately though, that means we only do 4096 bytes I/O per1071 * The overall request is limited to 240 sectors, matching the
1054 * MMC command. A future improvement would be to make the driver1072 * original vendor driver.
1055 * accept sg lists and entries of any size, and simply iterate
1056 * through them 4096 bytes at a time.
1057 */1073 */
1058 mmc->max_segs = AU6601_MAX_DMA_SEGMENTS;1074 mmc->max_segs = AU6601_MAX_DMA_SEGMENTS;
1059 mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE;1075 mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE;
1060 mmc->max_req_size = mmc->max_seg_size;1076 mmc->max_blk_count = 240;
1077 mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
1078 dma_set_max_seg_size(host->dev, mmc->max_seg_size);
1061}1079}
1062 1080
1063static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)1081static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
include/linux/alcor_pci.h+1−1
@@ -23,7 +23,7 @@ · 22 unmodified lines
23#define AU6601_BASE_CLOCK 3100000023#define AU6601_BASE_CLOCK 31000000
24#define AU6601_MIN_CLOCK 15000024#define AU6601_MIN_CLOCK 150000
25#define AU6601_MAX_CLOCK 20800000025#define AU6601_MAX_CLOCK 208000000
26#define AU6601_MAX_DMA_SEGMENTS 126#define AU6601_MAX_DMA_SEGMENTS 64
27#define AU6601_MAX_PIO_SEGMENTS 127#define AU6601_MAX_PIO_SEGMENTS 1
28#define AU6601_MAX_DMA_BLOCK_SIZE 0x100028#define AU6601_MAX_DMA_BLOCK_SIZE 0x1000
29#define AU6601_MAX_PIO_BLOCK_SIZE 0x20029#define AU6601_MAX_PIO_BLOCK_SIZE 0x200

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t