diff options
-rw-r--r-- | drivers/mmc/host/mmci.c | 187 |
1 files changed, 105 insertions, 82 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index dee9b73ce293..372e921389c8 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c | |||
@@ -149,6 +149,24 @@ static struct variant_data variant_ux500v2 = { | |||
149 | }; | 149 | }; |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * Validate mmc prerequisites | ||
153 | */ | ||
154 | static int mmci_validate_data(struct mmci_host *host, | ||
155 | struct mmc_data *data) | ||
156 | { | ||
157 | if (!data) | ||
158 | return 0; | ||
159 | |||
160 | if (!is_power_of_2(data->blksz)) { | ||
161 | dev_err(mmc_dev(host->mmc), | ||
162 | "unsupported block size (%d bytes)\n", data->blksz); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | /* | ||
152 | * This must be called with host->lock held | 170 | * This must be called with host->lock held |
153 | */ | 171 | */ |
154 | static void mmci_write_clkreg(struct mmci_host *host, u32 clk) | 172 | static void mmci_write_clkreg(struct mmci_host *host, u32 clk) |
@@ -370,10 +388,33 @@ static inline void mmci_dma_release(struct mmci_host *host) | |||
370 | host->dma_rx_channel = host->dma_tx_channel = NULL; | 388 | host->dma_rx_channel = host->dma_tx_channel = NULL; |
371 | } | 389 | } |
372 | 390 | ||
391 | static void mmci_dma_data_error(struct mmci_host *host) | ||
392 | { | ||
393 | dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); | ||
394 | dmaengine_terminate_all(host->dma_current); | ||
395 | host->dma_current = NULL; | ||
396 | host->dma_desc_current = NULL; | ||
397 | host->data->host_cookie = 0; | ||
398 | } | ||
399 | |||
373 | static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) | 400 | static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) |
374 | { | 401 | { |
375 | struct dma_chan *chan = host->dma_current; | 402 | struct dma_chan *chan; |
376 | enum dma_data_direction dir; | 403 | enum dma_data_direction dir; |
404 | |||
405 | if (data->flags & MMC_DATA_READ) { | ||
406 | dir = DMA_FROM_DEVICE; | ||
407 | chan = host->dma_rx_channel; | ||
408 | } else { | ||
409 | dir = DMA_TO_DEVICE; | ||
410 | chan = host->dma_tx_channel; | ||
411 | } | ||
412 | |||
413 | dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); | ||
414 | } | ||
415 | |||
416 | static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) | ||
417 | { | ||
377 | u32 status; | 418 | u32 status; |
378 | int i; | 419 | int i; |
379 | 420 | ||
@@ -392,19 +433,13 @@ static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) | |||
392 | * contiguous buffers. On TX, we'll get a FIFO underrun error. | 433 | * contiguous buffers. On TX, we'll get a FIFO underrun error. |
393 | */ | 434 | */ |
394 | if (status & MCI_RXDATAAVLBLMASK) { | 435 | if (status & MCI_RXDATAAVLBLMASK) { |
395 | dmaengine_terminate_all(chan); | 436 | mmci_dma_data_error(host); |
396 | if (!data->error) | 437 | if (!data->error) |
397 | data->error = -EIO; | 438 | data->error = -EIO; |
398 | } | 439 | } |
399 | 440 | ||
400 | if (data->flags & MMC_DATA_WRITE) { | ||
401 | dir = DMA_TO_DEVICE; | ||
402 | } else { | ||
403 | dir = DMA_FROM_DEVICE; | ||
404 | } | ||
405 | |||
406 | if (!data->host_cookie) | 441 | if (!data->host_cookie) |
407 | dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir); | 442 | mmci_dma_unmap(host, data); |
408 | 443 | ||
409 | /* | 444 | /* |
410 | * Use of DMA with scatter-gather is impossible. | 445 | * Use of DMA with scatter-gather is impossible. |
@@ -414,16 +449,15 @@ static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) | |||
414 | dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); | 449 | dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n"); |
415 | mmci_dma_release(host); | 450 | mmci_dma_release(host); |
416 | } | 451 | } |
417 | } | ||
418 | 452 | ||
419 | static void mmci_dma_data_error(struct mmci_host *host) | 453 | host->dma_current = NULL; |
420 | { | 454 | host->dma_desc_current = NULL; |
421 | dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); | ||
422 | dmaengine_terminate_all(host->dma_current); | ||
423 | } | 455 | } |
424 | 456 | ||
425 | static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, | 457 | /* prepares DMA channel and DMA descriptor, returns non-zero on failure */ |
426 | struct mmci_host_next *next) | 458 | static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, |
459 | struct dma_chan **dma_chan, | ||
460 | struct dma_async_tx_descriptor **dma_desc) | ||
427 | { | 461 | { |
428 | struct variant_data *variant = host->variant; | 462 | struct variant_data *variant = host->variant; |
429 | struct dma_slave_config conf = { | 463 | struct dma_slave_config conf = { |
@@ -441,16 +475,6 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, | |||
441 | enum dma_data_direction buffer_dirn; | 475 | enum dma_data_direction buffer_dirn; |
442 | int nr_sg; | 476 | int nr_sg; |
443 | 477 | ||
444 | /* Check if next job is already prepared */ | ||
445 | if (data->host_cookie && !next && | ||
446 | host->dma_current && host->dma_desc_current) | ||
447 | return 0; | ||
448 | |||
449 | if (!next) { | ||
450 | host->dma_current = NULL; | ||
451 | host->dma_desc_current = NULL; | ||
452 | } | ||
453 | |||
454 | if (data->flags & MMC_DATA_READ) { | 478 | if (data->flags & MMC_DATA_READ) { |
455 | conf.direction = DMA_DEV_TO_MEM; | 479 | conf.direction = DMA_DEV_TO_MEM; |
456 | buffer_dirn = DMA_FROM_DEVICE; | 480 | buffer_dirn = DMA_FROM_DEVICE; |
@@ -480,29 +504,41 @@ static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, | |||
480 | if (!desc) | 504 | if (!desc) |
481 | goto unmap_exit; | 505 | goto unmap_exit; |
482 | 506 | ||
483 | if (next) { | 507 | *dma_chan = chan; |
484 | next->dma_chan = chan; | 508 | *dma_desc = desc; |
485 | next->dma_desc = desc; | ||
486 | } else { | ||
487 | host->dma_current = chan; | ||
488 | host->dma_desc_current = desc; | ||
489 | } | ||
490 | 509 | ||
491 | return 0; | 510 | return 0; |
492 | 511 | ||
493 | unmap_exit: | 512 | unmap_exit: |
494 | if (!next) | ||
495 | dmaengine_terminate_all(chan); | ||
496 | dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn); | 513 | dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn); |
497 | return -ENOMEM; | 514 | return -ENOMEM; |
498 | } | 515 | } |
499 | 516 | ||
517 | static inline int mmci_dma_prep_data(struct mmci_host *host, | ||
518 | struct mmc_data *data) | ||
519 | { | ||
520 | /* Check if next job is already prepared. */ | ||
521 | if (host->dma_current && host->dma_desc_current) | ||
522 | return 0; | ||
523 | |||
524 | /* No job were prepared thus do it now. */ | ||
525 | return __mmci_dma_prep_data(host, data, &host->dma_current, | ||
526 | &host->dma_desc_current); | ||
527 | } | ||
528 | |||
529 | static inline int mmci_dma_prep_next(struct mmci_host *host, | ||
530 | struct mmc_data *data) | ||
531 | { | ||
532 | struct mmci_host_next *nd = &host->next_data; | ||
533 | return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); | ||
534 | } | ||
535 | |||
500 | static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) | 536 | static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) |
501 | { | 537 | { |
502 | int ret; | 538 | int ret; |
503 | struct mmc_data *data = host->data; | 539 | struct mmc_data *data = host->data; |
504 | 540 | ||
505 | ret = mmci_dma_prep_data(host, host->data, NULL); | 541 | ret = mmci_dma_prep_data(host, host->data); |
506 | if (ret) | 542 | if (ret) |
507 | return ret; | 543 | return ret; |
508 | 544 | ||
@@ -532,19 +568,11 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) | |||
532 | { | 568 | { |
533 | struct mmci_host_next *next = &host->next_data; | 569 | struct mmci_host_next *next = &host->next_data; |
534 | 570 | ||
535 | if (data->host_cookie && data->host_cookie != next->cookie) { | 571 | WARN_ON(data->host_cookie && data->host_cookie != next->cookie); |
536 | pr_warning("[%s] invalid cookie: data->host_cookie %d" | 572 | WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan)); |
537 | " host->next_data.cookie %d\n", | ||
538 | __func__, data->host_cookie, host->next_data.cookie); | ||
539 | data->host_cookie = 0; | ||
540 | } | ||
541 | |||
542 | if (!data->host_cookie) | ||
543 | return; | ||
544 | 573 | ||
545 | host->dma_desc_current = next->dma_desc; | 574 | host->dma_desc_current = next->dma_desc; |
546 | host->dma_current = next->dma_chan; | 575 | host->dma_current = next->dma_chan; |
547 | |||
548 | next->dma_desc = NULL; | 576 | next->dma_desc = NULL; |
549 | next->dma_chan = NULL; | 577 | next->dma_chan = NULL; |
550 | } | 578 | } |
@@ -559,19 +587,13 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq, | |||
559 | if (!data) | 587 | if (!data) |
560 | return; | 588 | return; |
561 | 589 | ||
562 | if (data->host_cookie) { | 590 | BUG_ON(data->host_cookie); |
563 | data->host_cookie = 0; | 591 | |
592 | if (mmci_validate_data(host, data)) | ||
564 | return; | 593 | return; |
565 | } | ||
566 | 594 | ||
567 | /* if config for dma */ | 595 | if (!mmci_dma_prep_next(host, data)) |
568 | if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) || | 596 | data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; |
569 | ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) { | ||
570 | if (mmci_dma_prep_data(host, data, nd)) | ||
571 | data->host_cookie = 0; | ||
572 | else | ||
573 | data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; | ||
574 | } | ||
575 | } | 597 | } |
576 | 598 | ||
577 | static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, | 599 | static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, |
@@ -579,29 +601,23 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, | |||
579 | { | 601 | { |
580 | struct mmci_host *host = mmc_priv(mmc); | 602 | struct mmci_host *host = mmc_priv(mmc); |
581 | struct mmc_data *data = mrq->data; | 603 | struct mmc_data *data = mrq->data; |
582 | struct dma_chan *chan; | ||
583 | enum dma_data_direction dir; | ||
584 | 604 | ||
585 | if (!data) | 605 | if (!data || !data->host_cookie) |
586 | return; | 606 | return; |
587 | 607 | ||
588 | if (data->flags & MMC_DATA_READ) { | 608 | mmci_dma_unmap(host, data); |
589 | dir = DMA_FROM_DEVICE; | ||
590 | chan = host->dma_rx_channel; | ||
591 | } else { | ||
592 | dir = DMA_TO_DEVICE; | ||
593 | chan = host->dma_tx_channel; | ||
594 | } | ||
595 | 609 | ||
610 | if (err) { | ||
611 | struct mmci_host_next *next = &host->next_data; | ||
612 | struct dma_chan *chan; | ||
613 | if (data->flags & MMC_DATA_READ) | ||
614 | chan = host->dma_rx_channel; | ||
615 | else | ||
616 | chan = host->dma_tx_channel; | ||
617 | dmaengine_terminate_all(chan); | ||
596 | 618 | ||
597 | /* if config for dma */ | 619 | next->dma_desc = NULL; |
598 | if (chan) { | 620 | next->dma_chan = NULL; |
599 | if (err) | ||
600 | dmaengine_terminate_all(chan); | ||
601 | if (data->host_cookie) | ||
602 | dma_unmap_sg(mmc_dev(host->mmc), data->sg, | ||
603 | data->sg_len, dir); | ||
604 | mrq->data->host_cookie = 0; | ||
605 | } | 621 | } |
606 | } | 622 | } |
607 | 623 | ||
@@ -622,6 +638,11 @@ static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) | |||
622 | { | 638 | { |
623 | } | 639 | } |
624 | 640 | ||
641 | static inline void mmci_dma_finalize(struct mmci_host *host, | ||
642 | struct mmc_data *data) | ||
643 | { | ||
644 | } | ||
645 | |||
625 | static inline void mmci_dma_data_error(struct mmci_host *host) | 646 | static inline void mmci_dma_data_error(struct mmci_host *host) |
626 | { | 647 | { |
627 | } | 648 | } |
@@ -772,8 +793,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
772 | u32 remain, success; | 793 | u32 remain, success; |
773 | 794 | ||
774 | /* Terminate the DMA transfer */ | 795 | /* Terminate the DMA transfer */ |
775 | if (dma_inprogress(host)) | 796 | if (dma_inprogress(host)) { |
776 | mmci_dma_data_error(host); | 797 | mmci_dma_data_error(host); |
798 | mmci_dma_unmap(host, data); | ||
799 | } | ||
777 | 800 | ||
778 | /* | 801 | /* |
779 | * Calculate how far we are into the transfer. Note that | 802 | * Calculate how far we are into the transfer. Note that |
@@ -812,7 +835,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
812 | 835 | ||
813 | if (status & MCI_DATAEND || data->error) { | 836 | if (status & MCI_DATAEND || data->error) { |
814 | if (dma_inprogress(host)) | 837 | if (dma_inprogress(host)) |
815 | mmci_dma_unmap(host, data); | 838 | mmci_dma_finalize(host, data); |
816 | mmci_stop_data(host); | 839 | mmci_stop_data(host); |
817 | 840 | ||
818 | if (!data->error) | 841 | if (!data->error) |
@@ -849,8 +872,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, | |||
849 | if (!cmd->data || cmd->error) { | 872 | if (!cmd->data || cmd->error) { |
850 | if (host->data) { | 873 | if (host->data) { |
851 | /* Terminate the DMA transfer */ | 874 | /* Terminate the DMA transfer */ |
852 | if (dma_inprogress(host)) | 875 | if (dma_inprogress(host)) { |
853 | mmci_dma_data_error(host); | 876 | mmci_dma_data_error(host); |
877 | mmci_dma_unmap(host, host->data); | ||
878 | } | ||
854 | mmci_stop_data(host); | 879 | mmci_stop_data(host); |
855 | } | 880 | } |
856 | mmci_request_end(host, cmd->mrq); | 881 | mmci_request_end(host, cmd->mrq); |
@@ -1076,10 +1101,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
1076 | 1101 | ||
1077 | WARN_ON(host->mrq != NULL); | 1102 | WARN_ON(host->mrq != NULL); |
1078 | 1103 | ||
1079 | if (mrq->data && !is_power_of_2(mrq->data->blksz)) { | 1104 | mrq->cmd->error = mmci_validate_data(host, mrq->data); |
1080 | dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n", | 1105 | if (mrq->cmd->error) { |
1081 | mrq->data->blksz); | ||
1082 | mrq->cmd->error = -EINVAL; | ||
1083 | mmc_request_done(mmc, mrq); | 1106 | mmc_request_done(mmc, mrq); |
1084 | return; | 1107 | return; |
1085 | } | 1108 | } |