diff options
author | Alex Dubov <oakad@yahoo.com> | 2007-04-12 03:05:25 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-01 07:04:15 -0400 |
commit | 13cdf48ef15befbd36f8295091b9e0f9bd322963 (patch) | |
tree | d1092ee1a8aaad0ee6feaf6e98f441315bc1f18e /drivers/mmc/tifm_sd.c | |
parent | 5897d657b58efb244b1f82a912ee93e5141ed14c (diff) |
tifm_sd: implement software scatter-gather
It was found that delays associated with issue and completion of the commands
severely limit performance of the new, fast SD cards. To alleviate this issue
scatter-gather emulation in software is implemented for both dma and pio
transfer modes. Non-block aligned and high memory sg entries are accounted
for.
Signed-off-by: Alex Dubov <oakad@yahoo.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/tifm_sd.c')
-rw-r--r-- | drivers/mmc/tifm_sd.c | 443 |
1 files changed, 296 insertions, 147 deletions
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index d20ccfcd911e..8e69514e415d 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/mmc/protocol.h> | 14 | #include <linux/mmc/protocol.h> |
15 | #include <linux/mmc/host.h> | 15 | #include <linux/mmc/host.h> |
16 | #include <linux/highmem.h> | 16 | #include <linux/highmem.h> |
17 | #include <linux/scatterlist.h> | ||
17 | #include <asm/io.h> | 18 | #include <asm/io.h> |
18 | 19 | ||
19 | #define DRIVER_NAME "tifm_sd" | 20 | #define DRIVER_NAME "tifm_sd" |
@@ -69,6 +70,8 @@ module_param(fixed_timeout, bool, 0644); | |||
69 | #define TIFM_MMCSD_CMD_AC 0x2000 | 70 | #define TIFM_MMCSD_CMD_AC 0x2000 |
70 | #define TIFM_MMCSD_CMD_ADTC 0x3000 | 71 | #define TIFM_MMCSD_CMD_ADTC 0x3000 |
71 | 72 | ||
73 | #define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL | ||
74 | |||
72 | enum { | 75 | enum { |
73 | CMD_READY = 0x0001, | 76 | CMD_READY = 0x0001, |
74 | FIFO_READY = 0x0002, | 77 | FIFO_READY = 0x0002, |
@@ -95,63 +98,227 @@ struct tifm_sd { | |||
95 | struct timer_list timer; | 98 | struct timer_list timer; |
96 | struct mmc_request *req; | 99 | struct mmc_request *req; |
97 | 100 | ||
98 | size_t written_blocks; | 101 | int sg_len; |
99 | size_t buffer_size; | 102 | int sg_pos; |
100 | size_t buffer_pos; | 103 | unsigned int block_pos; |
101 | 104 | struct scatterlist bounce_buf; | |
105 | unsigned char bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE]; | ||
102 | }; | 106 | }; |
103 | 107 | ||
104 | static char* tifm_sd_data_buffer(struct mmc_data *data) | 108 | /* for some reason, host won't respond correctly to readw/writew */ |
109 | static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, | ||
110 | unsigned int off, unsigned int cnt) | ||
105 | { | 111 | { |
106 | return page_address(data->sg->page) + data->sg->offset; | 112 | struct tifm_dev *sock = host->dev; |
113 | unsigned char *buf; | ||
114 | unsigned int pos = 0, val; | ||
115 | |||
116 | buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off; | ||
117 | if (host->cmd_flags & DATA_CARRY) { | ||
118 | buf[pos++] = host->bounce_buf_data[0]; | ||
119 | host->cmd_flags &= ~DATA_CARRY; | ||
120 | } | ||
121 | |||
122 | while (pos < cnt) { | ||
123 | val = readl(sock->addr + SOCK_MMCSD_DATA); | ||
124 | buf[pos++] = val & 0xff; | ||
125 | if (pos == cnt) { | ||
126 | host->bounce_buf_data[0] = (val >> 8) & 0xff; | ||
127 | host->cmd_flags |= DATA_CARRY; | ||
128 | break; | ||
129 | } | ||
130 | buf[pos++] = (val >> 8) & 0xff; | ||
131 | } | ||
132 | kunmap_atomic(buf - off, KM_BIO_DST_IRQ); | ||
107 | } | 133 | } |
108 | 134 | ||
109 | static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, | 135 | static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, |
110 | unsigned int host_status) | 136 | unsigned int off, unsigned int cnt) |
111 | { | 137 | { |
112 | struct mmc_command *cmd = host->req->cmd; | 138 | struct tifm_dev *sock = host->dev; |
113 | unsigned int t_val = 0, cnt = 0; | 139 | unsigned char *buf; |
114 | char *buffer; | 140 | unsigned int pos = 0, val; |
115 | 141 | ||
116 | if (host_status & TIFM_MMCSD_BRS) { | 142 | buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off; |
117 | /* in non-dma rx mode BRS fires when fifo is still not empty */ | 143 | if (host->cmd_flags & DATA_CARRY) { |
118 | if (host->no_dma && (cmd->data->flags & MMC_DATA_READ)) { | 144 | val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); |
119 | buffer = tifm_sd_data_buffer(host->req->data); | 145 | writel(val, sock->addr + SOCK_MMCSD_DATA); |
120 | while (host->buffer_size > host->buffer_pos) { | 146 | host->cmd_flags &= ~DATA_CARRY; |
121 | t_val = readl(sock->addr + SOCK_MMCSD_DATA); | 147 | } |
122 | buffer[host->buffer_pos++] = t_val & 0xff; | 148 | |
123 | buffer[host->buffer_pos++] = | 149 | while (pos < cnt) { |
124 | (t_val >> 8) & 0xff; | 150 | val = buf[pos++]; |
125 | } | 151 | if (pos == cnt) { |
152 | host->bounce_buf_data[0] = val & 0xff; | ||
153 | host->cmd_flags |= DATA_CARRY; | ||
154 | break; | ||
126 | } | 155 | } |
127 | return 1; | 156 | val |= (buf[pos++] << 8) & 0xff00; |
128 | } else if (host->no_dma) { | 157 | writel(val, sock->addr + SOCK_MMCSD_DATA); |
129 | buffer = tifm_sd_data_buffer(host->req->data); | 158 | } |
130 | if ((cmd->data->flags & MMC_DATA_READ) && | 159 | kunmap_atomic(buf - off, KM_BIO_SRC_IRQ); |
131 | (host_status & TIFM_MMCSD_AF)) { | 160 | } |
132 | for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { | 161 | |
133 | t_val = readl(sock->addr + SOCK_MMCSD_DATA); | 162 | static void tifm_sd_transfer_data(struct tifm_sd *host) |
134 | if (host->buffer_size > host->buffer_pos) { | 163 | { |
135 | buffer[host->buffer_pos++] = | 164 | struct mmc_data *r_data = host->req->cmd->data; |
136 | t_val & 0xff; | 165 | struct scatterlist *sg = r_data->sg; |
137 | buffer[host->buffer_pos++] = | 166 | unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2; |
138 | (t_val >> 8) & 0xff; | 167 | unsigned int p_off, p_cnt; |
139 | } | 168 | struct page *pg; |
140 | } | 169 | |
141 | } else if ((cmd->data->flags & MMC_DATA_WRITE) | 170 | if (host->sg_pos == host->sg_len) |
142 | && (host_status & TIFM_MMCSD_AE)) { | 171 | return; |
143 | for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { | 172 | while (t_size) { |
144 | if (host->buffer_size > host->buffer_pos) { | 173 | cnt = sg[host->sg_pos].length - host->block_pos; |
145 | t_val = buffer[host->buffer_pos++] | 174 | if (!cnt) { |
146 | & 0x00ff; | 175 | host->block_pos = 0; |
147 | t_val |= ((buffer[host->buffer_pos++]) | 176 | host->sg_pos++; |
148 | << 8) & 0xff00; | 177 | if (host->sg_pos == host->sg_len) { |
149 | writel(t_val, | 178 | if ((r_data->flags & MMC_DATA_WRITE) |
150 | sock->addr + SOCK_MMCSD_DATA); | 179 | && DATA_CARRY) |
151 | } | 180 | writel(host->bounce_buf_data[0], |
181 | host->dev->addr | ||
182 | + SOCK_MMCSD_DATA); | ||
183 | |||
184 | return; | ||
152 | } | 185 | } |
186 | cnt = sg[host->sg_pos].length; | ||
153 | } | 187 | } |
188 | off = sg[host->sg_pos].offset + host->block_pos; | ||
189 | |||
190 | pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT); | ||
191 | p_off = offset_in_page(off); | ||
192 | p_cnt = PAGE_SIZE - p_off; | ||
193 | p_cnt = min(p_cnt, cnt); | ||
194 | p_cnt = min(p_cnt, t_size); | ||
195 | |||
196 | if (r_data->flags & MMC_DATA_READ) | ||
197 | tifm_sd_read_fifo(host, pg, p_off, p_cnt); | ||
198 | else if (r_data->flags & MMC_DATA_WRITE) | ||
199 | tifm_sd_write_fifo(host, pg, p_off, p_cnt); | ||
200 | |||
201 | t_size -= p_cnt; | ||
202 | host->block_pos += p_cnt; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, | ||
207 | struct page *src, unsigned int src_off, | ||
208 | unsigned int count) | ||
209 | { | ||
210 | unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off; | ||
211 | unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off; | ||
212 | |||
213 | memcpy(dst_buf, src_buf, count); | ||
214 | |||
215 | kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ); | ||
216 | kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ); | ||
217 | } | ||
218 | |||
219 | static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) | ||
220 | { | ||
221 | struct scatterlist *sg = r_data->sg; | ||
222 | unsigned int t_size = r_data->blksz; | ||
223 | unsigned int off, cnt; | ||
224 | unsigned int p_off, p_cnt; | ||
225 | struct page *pg; | ||
226 | |||
227 | dev_dbg(&host->dev->dev, "bouncing block\n"); | ||
228 | while (t_size) { | ||
229 | cnt = sg[host->sg_pos].length - host->block_pos; | ||
230 | if (!cnt) { | ||
231 | host->block_pos = 0; | ||
232 | host->sg_pos++; | ||
233 | if (host->sg_pos == host->sg_len) | ||
234 | return; | ||
235 | cnt = sg[host->sg_pos].length; | ||
236 | } | ||
237 | off = sg[host->sg_pos].offset + host->block_pos; | ||
238 | |||
239 | pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT); | ||
240 | p_off = offset_in_page(off); | ||
241 | p_cnt = PAGE_SIZE - p_off; | ||
242 | p_cnt = min(p_cnt, cnt); | ||
243 | p_cnt = min(p_cnt, t_size); | ||
244 | |||
245 | if (r_data->flags & MMC_DATA_WRITE) | ||
246 | tifm_sd_copy_page(host->bounce_buf.page, | ||
247 | r_data->blksz - t_size, | ||
248 | pg, p_off, p_cnt); | ||
249 | else if (r_data->flags & MMC_DATA_READ) | ||
250 | tifm_sd_copy_page(pg, p_off, host->bounce_buf.page, | ||
251 | r_data->blksz - t_size, p_cnt); | ||
252 | |||
253 | t_size -= p_cnt; | ||
254 | host->block_pos += p_cnt; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data) | ||
259 | { | ||
260 | struct tifm_dev *sock = host->dev; | ||
261 | unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz; | ||
262 | unsigned int dma_len, dma_blk_cnt, dma_off; | ||
263 | struct scatterlist *sg = NULL; | ||
264 | unsigned long flags; | ||
265 | |||
266 | if (host->sg_pos == host->sg_len) | ||
267 | return 1; | ||
268 | |||
269 | if (host->cmd_flags & DATA_CARRY) { | ||
270 | host->cmd_flags &= ~DATA_CARRY; | ||
271 | local_irq_save(flags); | ||
272 | tifm_sd_bounce_block(host, r_data); | ||
273 | local_irq_restore(flags); | ||
274 | if (host->sg_pos == host->sg_len) | ||
275 | return 1; | ||
276 | } | ||
277 | |||
278 | dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos; | ||
279 | if (!dma_len) { | ||
280 | host->block_pos = 0; | ||
281 | host->sg_pos++; | ||
282 | if (host->sg_pos == host->sg_len) | ||
283 | return 1; | ||
284 | dma_len = sg_dma_len(&r_data->sg[host->sg_pos]); | ||
285 | } | ||
286 | |||
287 | if (dma_len < t_size) { | ||
288 | dma_blk_cnt = dma_len / r_data->blksz; | ||
289 | dma_off = host->block_pos; | ||
290 | host->block_pos += dma_blk_cnt * r_data->blksz; | ||
291 | } else { | ||
292 | dma_blk_cnt = TIFM_DMA_TSIZE; | ||
293 | dma_off = host->block_pos; | ||
294 | host->block_pos += t_size; | ||
154 | } | 295 | } |
296 | |||
297 | if (dma_blk_cnt) | ||
298 | sg = &r_data->sg[host->sg_pos]; | ||
299 | else if (dma_len) { | ||
300 | if (r_data->flags & MMC_DATA_WRITE) { | ||
301 | local_irq_save(flags); | ||
302 | tifm_sd_bounce_block(host, r_data); | ||
303 | local_irq_restore(flags); | ||
304 | } else | ||
305 | host->cmd_flags |= DATA_CARRY; | ||
306 | |||
307 | sg = &host->bounce_buf; | ||
308 | dma_off = 0; | ||
309 | dma_blk_cnt = 1; | ||
310 | } else | ||
311 | return 1; | ||
312 | |||
313 | dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt); | ||
314 | writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS); | ||
315 | if (r_data->flags & MMC_DATA_WRITE) | ||
316 | writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN, | ||
317 | sock->addr + SOCK_DMA_CONTROL); | ||
318 | else | ||
319 | writel((dma_blk_cnt << 8) | TIFM_DMA_EN, | ||
320 | sock->addr + SOCK_DMA_CONTROL); | ||
321 | |||
155 | return 0; | 322 | return 0; |
156 | } | 323 | } |
157 | 324 | ||
@@ -317,8 +484,10 @@ static void tifm_sd_data_event(struct tifm_dev *sock) | |||
317 | r_data = host->req->cmd->data; | 484 | r_data = host->req->cmd->data; |
318 | 485 | ||
319 | if (r_data && (fifo_status & TIFM_FIFO_READY)) { | 486 | if (r_data && (fifo_status & TIFM_FIFO_READY)) { |
320 | host->cmd_flags |= FIFO_READY; | 487 | if (tifm_sd_set_dma_data(host, r_data)) { |
321 | tifm_sd_check_status(host); | 488 | host->cmd_flags |= FIFO_READY; |
489 | tifm_sd_check_status(host); | ||
490 | } | ||
322 | } | 491 | } |
323 | } | 492 | } |
324 | 493 | ||
@@ -398,7 +567,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock) | |||
398 | if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF | 567 | if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF |
399 | | TIFM_MMCSD_BRS)) { | 568 | | TIFM_MMCSD_BRS)) { |
400 | local_irq_save(flags); | 569 | local_irq_save(flags); |
401 | tifm_sd_transfer_data(sock, host, host_status); | 570 | tifm_sd_transfer_data(host); |
402 | local_irq_restore(flags); | 571 | local_irq_restore(flags); |
403 | host_status &= ~TIFM_MMCSD_AE; | 572 | host_status &= ~TIFM_MMCSD_AE; |
404 | } | 573 | } |
@@ -416,38 +585,6 @@ done: | |||
416 | spin_unlock(&sock->lock); | 585 | spin_unlock(&sock->lock); |
417 | } | 586 | } |
418 | 587 | ||
419 | static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) | ||
420 | { | ||
421 | struct tifm_dev *sock = host->dev; | ||
422 | unsigned int dest_cnt; | ||
423 | |||
424 | /* DMA style IO */ | ||
425 | dev_dbg(&sock->dev, "setting dma for %d blocks\n", | ||
426 | cmd->data->blocks); | ||
427 | writel(TIFM_FIFO_INT_SETALL, | ||
428 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); | ||
429 | writel(ilog2(cmd->data->blksz) - 2, | ||
430 | sock->addr + SOCK_FIFO_PAGE_SIZE); | ||
431 | writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); | ||
432 | writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); | ||
433 | |||
434 | dest_cnt = (cmd->data->blocks) << 8; | ||
435 | |||
436 | writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS); | ||
437 | |||
438 | writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS); | ||
439 | writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN); | ||
440 | |||
441 | if (cmd->data->flags & MMC_DATA_WRITE) { | ||
442 | writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | ||
443 | writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, | ||
444 | sock->addr + SOCK_DMA_CONTROL); | ||
445 | } else { | ||
446 | writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | ||
447 | writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void tifm_sd_set_data_timeout(struct tifm_sd *host, | 588 | static void tifm_sd_set_data_timeout(struct tifm_sd *host, |
452 | struct mmc_data *data) | 589 | struct mmc_data *data) |
453 | { | 590 | { |
@@ -481,7 +618,6 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
481 | struct tifm_sd *host = mmc_priv(mmc); | 618 | struct tifm_sd *host = mmc_priv(mmc); |
482 | struct tifm_dev *sock = host->dev; | 619 | struct tifm_dev *sock = host->dev; |
483 | unsigned long flags; | 620 | unsigned long flags; |
484 | int sg_count = 0; | ||
485 | struct mmc_data *r_data = mrq->cmd->data; | 621 | struct mmc_data *r_data = mrq->cmd->data; |
486 | 622 | ||
487 | spin_lock_irqsave(&sock->lock, flags); | 623 | spin_lock_irqsave(&sock->lock, flags); |
@@ -496,13 +632,19 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
496 | goto err_out; | 632 | goto err_out; |
497 | } | 633 | } |
498 | 634 | ||
635 | host->cmd_flags = 0; | ||
636 | host->block_pos = 0; | ||
637 | host->sg_pos = 0; | ||
638 | |||
499 | if (r_data) { | 639 | if (r_data) { |
500 | tifm_sd_set_data_timeout(host, r_data); | 640 | tifm_sd_set_data_timeout(host, r_data); |
501 | 641 | ||
502 | if (host->no_dma) { | 642 | if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop) |
503 | host->buffer_size = mrq->cmd->data->blocks | 643 | writel(TIFM_MMCSD_EOFB |
504 | * mrq->cmd->data->blksz; | 644 | | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), |
645 | sock->addr + SOCK_MMCSD_INT_ENABLE); | ||
505 | 646 | ||
647 | if (host->no_dma) { | ||
506 | writel(TIFM_MMCSD_BUFINT | 648 | writel(TIFM_MMCSD_BUFINT |
507 | | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), | 649 | | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), |
508 | sock->addr + SOCK_MMCSD_INT_ENABLE); | 650 | sock->addr + SOCK_MMCSD_INT_ENABLE); |
@@ -510,34 +652,64 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
510 | | (TIFM_MMCSD_FIFO_SIZE - 1), | 652 | | (TIFM_MMCSD_FIFO_SIZE - 1), |
511 | sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | 653 | sock->addr + SOCK_MMCSD_BUFFER_CONFIG); |
512 | 654 | ||
513 | host->written_blocks = 0; | 655 | host->sg_len = r_data->sg_len; |
514 | host->cmd_flags &= ~CARD_BUSY; | ||
515 | host->buffer_pos = 0; | ||
516 | writel(r_data->blocks - 1, | ||
517 | sock->addr + SOCK_MMCSD_NUM_BLOCKS); | ||
518 | writel(r_data->blksz - 1, | ||
519 | sock->addr + SOCK_MMCSD_BLOCK_LEN); | ||
520 | } else { | 656 | } else { |
521 | sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len, | 657 | sg_init_one(&host->bounce_buf, host->bounce_buf_data, |
522 | mrq->cmd->flags & MMC_DATA_WRITE | 658 | r_data->blksz); |
523 | ? PCI_DMA_TODEVICE | 659 | |
524 | : PCI_DMA_FROMDEVICE); | 660 | if(1 != tifm_map_sg(sock, &host->bounce_buf, 1, |
525 | if (sg_count != 1) { | 661 | r_data->flags & MMC_DATA_WRITE |
526 | printk(KERN_ERR DRIVER_NAME | 662 | ? PCI_DMA_TODEVICE |
527 | ": scatterlist map failed\n"); | 663 | : PCI_DMA_FROMDEVICE)) { |
664 | printk(KERN_ERR "%s : scatterlist map failed\n", | ||
665 | sock->dev.bus_id); | ||
666 | spin_unlock_irqrestore(&sock->lock, flags); | ||
667 | goto err_out; | ||
668 | } | ||
669 | host->sg_len = tifm_map_sg(sock, r_data->sg, | ||
670 | r_data->sg_len, | ||
671 | r_data->flags | ||
672 | & MMC_DATA_WRITE | ||
673 | ? PCI_DMA_TODEVICE | ||
674 | : PCI_DMA_FROMDEVICE); | ||
675 | if (host->sg_len < 1) { | ||
676 | printk(KERN_ERR "%s : scatterlist map failed\n", | ||
677 | sock->dev.bus_id); | ||
678 | tifm_unmap_sg(sock, &host->bounce_buf, 1, | ||
679 | r_data->flags & MMC_DATA_WRITE | ||
680 | ? PCI_DMA_TODEVICE | ||
681 | : PCI_DMA_FROMDEVICE); | ||
528 | spin_unlock_irqrestore(&sock->lock, flags); | 682 | spin_unlock_irqrestore(&sock->lock, flags); |
529 | goto err_out; | 683 | goto err_out; |
530 | } | 684 | } |
531 | 685 | ||
532 | host->written_blocks = 0; | 686 | writel(TIFM_FIFO_INT_SETALL, |
533 | host->cmd_flags &= ~CARD_BUSY; | 687 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); |
534 | tifm_sd_prepare_data(host, mrq->cmd); | 688 | writel(ilog2(r_data->blksz) - 2, |
689 | sock->addr + SOCK_FIFO_PAGE_SIZE); | ||
690 | writel(TIFM_FIFO_ENABLE, | ||
691 | sock->addr + SOCK_FIFO_CONTROL); | ||
692 | writel(TIFM_FIFO_INTMASK, | ||
693 | sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); | ||
694 | |||
695 | if (r_data->flags & MMC_DATA_WRITE) | ||
696 | writel(TIFM_MMCSD_TXDE, | ||
697 | sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | ||
698 | else | ||
699 | writel(TIFM_MMCSD_RXDE, | ||
700 | sock->addr + SOCK_MMCSD_BUFFER_CONFIG); | ||
701 | |||
702 | tifm_sd_set_dma_data(host, r_data); | ||
535 | } | 703 | } |
704 | |||
705 | writel(r_data->blocks - 1, | ||
706 | sock->addr + SOCK_MMCSD_NUM_BLOCKS); | ||
707 | writel(r_data->blksz - 1, | ||
708 | sock->addr + SOCK_MMCSD_BLOCK_LEN); | ||
536 | } | 709 | } |
537 | 710 | ||
538 | host->req = mrq; | 711 | host->req = mrq; |
539 | mod_timer(&host->timer, jiffies + host->timeout_jiffies); | 712 | mod_timer(&host->timer, jiffies + host->timeout_jiffies); |
540 | host->cmd_flags = 0; | ||
541 | writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), | 713 | writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), |
542 | sock->addr + SOCK_CONTROL); | 714 | sock->addr + SOCK_CONTROL); |
543 | tifm_sd_exec(host, mrq->cmd); | 715 | tifm_sd_exec(host, mrq->cmd); |
@@ -545,11 +717,6 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
545 | return; | 717 | return; |
546 | 718 | ||
547 | err_out: | 719 | err_out: |
548 | if (sg_count > 0) | ||
549 | tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, | ||
550 | (r_data->flags & MMC_DATA_WRITE) | ||
551 | ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); | ||
552 | |||
553 | mrq->cmd->error = MMC_ERR_TIMEOUT; | 720 | mrq->cmd->error = MMC_ERR_TIMEOUT; |
554 | mmc_request_done(mmc, mrq); | 721 | mmc_request_done(mmc, mrq); |
555 | } | 722 | } |
@@ -578,40 +745,23 @@ static void tifm_sd_end_cmd(unsigned long data) | |||
578 | r_data = mrq->cmd->data; | 745 | r_data = mrq->cmd->data; |
579 | if (r_data) { | 746 | if (r_data) { |
580 | if (host->no_dma) { | 747 | if (host->no_dma) { |
581 | writel((~TIFM_MMCSD_BUFINT) & | 748 | writel((~TIFM_MMCSD_BUFINT) |
582 | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), | 749 | & readl(sock->addr + SOCK_MMCSD_INT_ENABLE), |
583 | sock->addr + SOCK_MMCSD_INT_ENABLE); | 750 | sock->addr + SOCK_MMCSD_INT_ENABLE); |
584 | |||
585 | if (r_data->flags & MMC_DATA_WRITE) { | ||
586 | r_data->bytes_xfered = host->written_blocks | ||
587 | * r_data->blksz; | ||
588 | } else { | ||
589 | r_data->bytes_xfered = r_data->blocks - | ||
590 | readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) | ||
591 | - 1; | ||
592 | r_data->bytes_xfered *= r_data->blksz; | ||
593 | r_data->bytes_xfered += r_data->blksz | ||
594 | - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) | ||
595 | + 1; | ||
596 | } | ||
597 | host->buffer_pos = 0; | ||
598 | host->buffer_size = 0; | ||
599 | } else { | 751 | } else { |
600 | if (r_data->flags & MMC_DATA_WRITE) { | 752 | tifm_unmap_sg(sock, &host->bounce_buf, 1, |
601 | r_data->bytes_xfered = host->written_blocks | 753 | (r_data->flags & MMC_DATA_WRITE) |
602 | * r_data->blksz; | 754 | ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); |
603 | } else { | ||
604 | r_data->bytes_xfered = r_data->blocks - | ||
605 | readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; | ||
606 | r_data->bytes_xfered *= r_data->blksz; | ||
607 | r_data->bytes_xfered += r_data->blksz - | ||
608 | readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) | ||
609 | + 1; | ||
610 | } | ||
611 | tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, | 755 | tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, |
612 | (r_data->flags & MMC_DATA_WRITE) | 756 | (r_data->flags & MMC_DATA_WRITE) |
613 | ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); | 757 | ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); |
614 | } | 758 | } |
759 | |||
760 | r_data->bytes_xfered = r_data->blocks | ||
761 | - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; | ||
762 | r_data->bytes_xfered *= r_data->blksz; | ||
763 | r_data->bytes_xfered += r_data->blksz | ||
764 | - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; | ||
615 | } | 765 | } |
616 | 766 | ||
617 | writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), | 767 | writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), |
@@ -810,15 +960,14 @@ static int tifm_sd_probe(struct tifm_dev *sock) | |||
810 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; | 960 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; |
811 | mmc->f_min = 20000000 / 60; | 961 | mmc->f_min = 20000000 / 60; |
812 | mmc->f_max = 24000000; | 962 | mmc->f_max = 24000000; |
813 | mmc->max_hw_segs = 1; | 963 | |
814 | mmc->max_phys_segs = 1; | 964 | mmc->max_blk_count = 2048; |
815 | // limited by DMA counter - it's safer to stick with | 965 | mmc->max_hw_segs = mmc->max_blk_count; |
816 | // block counter has 11 bits though | 966 | mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE); |
817 | mmc->max_blk_count = 256; | 967 | mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size; |
818 | // 2k maximum hw block length | 968 | mmc->max_req_size = mmc->max_seg_size; |
819 | mmc->max_blk_size = 2048; | 969 | mmc->max_phys_segs = mmc->max_hw_segs; |
820 | mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; | 970 | |
821 | mmc->max_seg_size = mmc->max_req_size; | ||
822 | sock->card_event = tifm_sd_card_event; | 971 | sock->card_event = tifm_sd_card_event; |
823 | sock->data_event = tifm_sd_data_event; | 972 | sock->data_event = tifm_sd_data_event; |
824 | rc = tifm_sd_initialize_host(host); | 973 | rc = tifm_sd_initialize_host(host); |