diff options
author | Andy Ross <andy.ross@windriver.com> | 2011-01-03 13:36:56 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-01-08 23:52:25 -0500 |
commit | 807e8e40673d9628fa7dcdd14423424b4ee5f43b (patch) | |
tree | ca95bdb69d07f0169bbfc5388e15745b9811513e /drivers/mmc/core | |
parent | 08c82dfad2458f8f9b83126224a85e7ea9e2b046 (diff) |
mmc: Fix sd/sdio/mmc initialization frequency retries
Rewrite and clean up mmc_rescan() to properly retry frequencies lower
than 400kHz. Failures can happen both in sd_send_* calls and
mmc_attach_*. Break out "mmc_rescan_try_freq" from the frequency
selection loop. Symmetrize claim/release logic in mmc_attach_* API,
and move the sd_send_* calls there to make mmc_rescan easier to read.
Signed-off-by: Andy Ross <andy.ross@windriver.com>
Reviewed-and-Tested-by: Hein Tibosch <hein_tibosch@yahoo.es>
Reviewed-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/core.c | 119 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 6 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 13 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 11 | ||||
-rw-r--r-- | drivers/mmc/core/sdio.c | 18 |
5 files changed, 68 insertions, 99 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 97e0624eb9b6..198f70bad908 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -1485,25 +1485,41 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) | |||
1485 | } | 1485 | } |
1486 | EXPORT_SYMBOL(mmc_set_blocklen); | 1486 | EXPORT_SYMBOL(mmc_set_blocklen); |
1487 | 1487 | ||
1488 | static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | ||
1489 | { | ||
1490 | host->f_init = freq; | ||
1491 | |||
1492 | #ifdef CONFIG_MMC_DEBUG | ||
1493 | pr_info("%s: %s: trying to init card at %u Hz\n", | ||
1494 | mmc_hostname(host), __func__, host->f_init); | ||
1495 | #endif | ||
1496 | mmc_power_up(host); | ||
1497 | sdio_reset(host); | ||
1498 | mmc_go_idle(host); | ||
1499 | |||
1500 | mmc_send_if_cond(host, host->ocr_avail); | ||
1501 | |||
1502 | /* Order's important: probe SDIO, then SD, then MMC */ | ||
1503 | if (!mmc_attach_sdio(host)) | ||
1504 | return 0; | ||
1505 | if (!mmc_attach_sd(host)) | ||
1506 | return 0; | ||
1507 | if (!mmc_attach_mmc(host)) | ||
1508 | return 0; | ||
1509 | |||
1510 | mmc_power_off(host); | ||
1511 | return -EIO; | ||
1512 | } | ||
1513 | |||
1488 | void mmc_rescan(struct work_struct *work) | 1514 | void mmc_rescan(struct work_struct *work) |
1489 | { | 1515 | { |
1516 | static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
1490 | struct mmc_host *host = | 1517 | struct mmc_host *host = |
1491 | container_of(work, struct mmc_host, detect.work); | 1518 | container_of(work, struct mmc_host, detect.work); |
1492 | u32 ocr; | ||
1493 | int err; | ||
1494 | unsigned long flags; | ||
1495 | int i; | 1519 | int i; |
1496 | const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; | ||
1497 | |||
1498 | spin_lock_irqsave(&host->lock, flags); | ||
1499 | 1520 | ||
1500 | if (host->rescan_disable) { | 1521 | if (host->rescan_disable) |
1501 | spin_unlock_irqrestore(&host->lock, flags); | ||
1502 | return; | 1522 | return; |
1503 | } | ||
1504 | |||
1505 | spin_unlock_irqrestore(&host->lock, flags); | ||
1506 | |||
1507 | 1523 | ||
1508 | mmc_bus_get(host); | 1524 | mmc_bus_get(host); |
1509 | 1525 | ||
@@ -1526,8 +1542,6 @@ void mmc_rescan(struct work_struct *work) | |||
1526 | goto out; | 1542 | goto out; |
1527 | } | 1543 | } |
1528 | 1544 | ||
1529 | /* detect a newly inserted card */ | ||
1530 | |||
1531 | /* | 1545 | /* |
1532 | * Only we can add a new handler, so it's safe to | 1546 | * Only we can add a new handler, so it's safe to |
1533 | * release the lock here. | 1547 | * release the lock here. |
@@ -1537,77 +1551,16 @@ void mmc_rescan(struct work_struct *work) | |||
1537 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) | 1551 | if (host->ops->get_cd && host->ops->get_cd(host) == 0) |
1538 | goto out; | 1552 | goto out; |
1539 | 1553 | ||
1554 | mmc_claim_host(host); | ||
1540 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { | 1555 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { |
1541 | mmc_claim_host(host); | 1556 | if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) |
1542 | 1557 | break; | |
1543 | if (freqs[i] >= host->f_min) | 1558 | if (freqs[i] < host->f_min) |
1544 | host->f_init = freqs[i]; | 1559 | break; |
1545 | else if (!i || freqs[i-1] > host->f_min) | ||
1546 | host->f_init = host->f_min; | ||
1547 | else { | ||
1548 | mmc_release_host(host); | ||
1549 | goto out; | ||
1550 | } | ||
1551 | #ifdef CONFIG_MMC_DEBUG | ||
1552 | pr_info("%s: %s: trying to init card at %u Hz\n", | ||
1553 | mmc_hostname(host), __func__, host->f_init); | ||
1554 | #endif | ||
1555 | mmc_power_up(host); | ||
1556 | sdio_reset(host); | ||
1557 | mmc_go_idle(host); | ||
1558 | |||
1559 | mmc_send_if_cond(host, host->ocr_avail); | ||
1560 | |||
1561 | /* | ||
1562 | * First we search for SDIO... | ||
1563 | */ | ||
1564 | err = mmc_send_io_op_cond(host, 0, &ocr); | ||
1565 | if (!err) { | ||
1566 | if (mmc_attach_sdio(host, ocr)) { | ||
1567 | mmc_claim_host(host); | ||
1568 | /* | ||
1569 | * Try SDMEM (but not MMC) even if SDIO | ||
1570 | * is broken. | ||
1571 | */ | ||
1572 | mmc_power_up(host); | ||
1573 | sdio_reset(host); | ||
1574 | mmc_go_idle(host); | ||
1575 | mmc_send_if_cond(host, host->ocr_avail); | ||
1576 | |||
1577 | if (mmc_send_app_op_cond(host, 0, &ocr)) | ||
1578 | goto out_fail; | ||
1579 | |||
1580 | if (mmc_attach_sd(host, ocr)) | ||
1581 | mmc_power_off(host); | ||
1582 | } | ||
1583 | goto out; | ||
1584 | } | ||
1585 | |||
1586 | /* | ||
1587 | * ...then normal SD... | ||
1588 | */ | ||
1589 | err = mmc_send_app_op_cond(host, 0, &ocr); | ||
1590 | if (!err) { | ||
1591 | if (mmc_attach_sd(host, ocr)) | ||
1592 | mmc_power_off(host); | ||
1593 | goto out; | ||
1594 | } | ||
1595 | |||
1596 | /* | ||
1597 | * ...and finally MMC. | ||
1598 | */ | ||
1599 | err = mmc_send_op_cond(host, 0, &ocr); | ||
1600 | if (!err) { | ||
1601 | if (mmc_attach_mmc(host, ocr)) | ||
1602 | mmc_power_off(host); | ||
1603 | goto out; | ||
1604 | } | ||
1605 | |||
1606 | out_fail: | ||
1607 | mmc_release_host(host); | ||
1608 | mmc_power_off(host); | ||
1609 | } | 1560 | } |
1610 | out: | 1561 | mmc_release_host(host); |
1562 | |||
1563 | out: | ||
1611 | if (host->caps & MMC_CAP_NEEDS_POLL) | 1564 | if (host->caps & MMC_CAP_NEEDS_POLL) |
1612 | mmc_schedule_delayed_work(&host->detect, HZ); | 1565 | mmc_schedule_delayed_work(&host->detect, HZ); |
1613 | } | 1566 | } |
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 026c975b99a9..ca1fdde29df6 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h | |||
@@ -57,9 +57,9 @@ void mmc_rescan(struct work_struct *work); | |||
57 | void mmc_start_host(struct mmc_host *host); | 57 | void mmc_start_host(struct mmc_host *host); |
58 | void mmc_stop_host(struct mmc_host *host); | 58 | void mmc_stop_host(struct mmc_host *host); |
59 | 59 | ||
60 | int mmc_attach_mmc(struct mmc_host *host, u32 ocr); | 60 | int mmc_attach_mmc(struct mmc_host *host); |
61 | int mmc_attach_sd(struct mmc_host *host, u32 ocr); | 61 | int mmc_attach_sd(struct mmc_host *host); |
62 | int mmc_attach_sdio(struct mmc_host *host, u32 ocr); | 62 | int mmc_attach_sdio(struct mmc_host *host); |
63 | 63 | ||
64 | /* Module parameters */ | 64 | /* Module parameters */ |
65 | extern int use_spi_crc; | 65 | extern int use_spi_crc; |
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c86dd7384d7d..16006ef153fe 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
@@ -755,13 +755,18 @@ static void mmc_attach_bus_ops(struct mmc_host *host) | |||
755 | /* | 755 | /* |
756 | * Starting point for MMC card init. | 756 | * Starting point for MMC card init. |
757 | */ | 757 | */ |
758 | int mmc_attach_mmc(struct mmc_host *host, u32 ocr) | 758 | int mmc_attach_mmc(struct mmc_host *host) |
759 | { | 759 | { |
760 | int err; | 760 | int err; |
761 | u32 ocr; | ||
761 | 762 | ||
762 | BUG_ON(!host); | 763 | BUG_ON(!host); |
763 | WARN_ON(!host->claimed); | 764 | WARN_ON(!host->claimed); |
764 | 765 | ||
766 | err = mmc_send_op_cond(host, 0, &ocr); | ||
767 | if (err) | ||
768 | return err; | ||
769 | |||
765 | mmc_attach_bus_ops(host); | 770 | mmc_attach_bus_ops(host); |
766 | if (host->ocr_avail_mmc) | 771 | if (host->ocr_avail_mmc) |
767 | host->ocr_avail = host->ocr_avail_mmc; | 772 | host->ocr_avail = host->ocr_avail_mmc; |
@@ -804,20 +809,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr) | |||
804 | goto err; | 809 | goto err; |
805 | 810 | ||
806 | mmc_release_host(host); | 811 | mmc_release_host(host); |
807 | |||
808 | err = mmc_add_card(host->card); | 812 | err = mmc_add_card(host->card); |
813 | mmc_claim_host(host); | ||
809 | if (err) | 814 | if (err) |
810 | goto remove_card; | 815 | goto remove_card; |
811 | 816 | ||
812 | return 0; | 817 | return 0; |
813 | 818 | ||
814 | remove_card: | 819 | remove_card: |
820 | mmc_release_host(host); | ||
815 | mmc_remove_card(host->card); | 821 | mmc_remove_card(host->card); |
816 | host->card = NULL; | ||
817 | mmc_claim_host(host); | 822 | mmc_claim_host(host); |
823 | host->card = NULL; | ||
818 | err: | 824 | err: |
819 | mmc_detach_bus(host); | 825 | mmc_detach_bus(host); |
820 | mmc_release_host(host); | ||
821 | 826 | ||
822 | printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", | 827 | printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", |
823 | mmc_hostname(host), err); | 828 | mmc_hostname(host), err); |
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index de062ebd8b26..d18c32bca99b 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
@@ -764,13 +764,18 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host) | |||
764 | /* | 764 | /* |
765 | * Starting point for SD card init. | 765 | * Starting point for SD card init. |
766 | */ | 766 | */ |
767 | int mmc_attach_sd(struct mmc_host *host, u32 ocr) | 767 | int mmc_attach_sd(struct mmc_host *host) |
768 | { | 768 | { |
769 | int err; | 769 | int err; |
770 | u32 ocr; | ||
770 | 771 | ||
771 | BUG_ON(!host); | 772 | BUG_ON(!host); |
772 | WARN_ON(!host->claimed); | 773 | WARN_ON(!host->claimed); |
773 | 774 | ||
775 | err = mmc_send_app_op_cond(host, 0, &ocr); | ||
776 | if (err) | ||
777 | return err; | ||
778 | |||
774 | mmc_sd_attach_bus_ops(host); | 779 | mmc_sd_attach_bus_ops(host); |
775 | if (host->ocr_avail_sd) | 780 | if (host->ocr_avail_sd) |
776 | host->ocr_avail = host->ocr_avail_sd; | 781 | host->ocr_avail = host->ocr_avail_sd; |
@@ -823,20 +828,20 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
823 | goto err; | 828 | goto err; |
824 | 829 | ||
825 | mmc_release_host(host); | 830 | mmc_release_host(host); |
826 | |||
827 | err = mmc_add_card(host->card); | 831 | err = mmc_add_card(host->card); |
832 | mmc_claim_host(host); | ||
828 | if (err) | 833 | if (err) |
829 | goto remove_card; | 834 | goto remove_card; |
830 | 835 | ||
831 | return 0; | 836 | return 0; |
832 | 837 | ||
833 | remove_card: | 838 | remove_card: |
839 | mmc_release_host(host); | ||
834 | mmc_remove_card(host->card); | 840 | mmc_remove_card(host->card); |
835 | host->card = NULL; | 841 | host->card = NULL; |
836 | mmc_claim_host(host); | 842 | mmc_claim_host(host); |
837 | err: | 843 | err: |
838 | mmc_detach_bus(host); | 844 | mmc_detach_bus(host); |
839 | mmc_release_host(host); | ||
840 | 845 | ||
841 | printk(KERN_ERR "%s: error %d whilst initialising SD card\n", | 846 | printk(KERN_ERR "%s: error %d whilst initialising SD card\n", |
842 | mmc_hostname(host), err); | 847 | mmc_hostname(host), err); |
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 82f4b9008987..5c4a54d9b6a4 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
@@ -702,15 +702,19 @@ static const struct mmc_bus_ops mmc_sdio_ops = { | |||
702 | /* | 702 | /* |
703 | * Starting point for SDIO card init. | 703 | * Starting point for SDIO card init. |
704 | */ | 704 | */ |
705 | int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | 705 | int mmc_attach_sdio(struct mmc_host *host) |
706 | { | 706 | { |
707 | int err; | 707 | int err, i, funcs; |
708 | int i, funcs; | 708 | u32 ocr; |
709 | struct mmc_card *card; | 709 | struct mmc_card *card; |
710 | 710 | ||
711 | BUG_ON(!host); | 711 | BUG_ON(!host); |
712 | WARN_ON(!host->claimed); | 712 | WARN_ON(!host->claimed); |
713 | 713 | ||
714 | err = mmc_send_io_op_cond(host, 0, &ocr); | ||
715 | if (err) | ||
716 | return err; | ||
717 | |||
714 | mmc_attach_bus(host, &mmc_sdio_ops); | 718 | mmc_attach_bus(host, &mmc_sdio_ops); |
715 | if (host->ocr_avail_sdio) | 719 | if (host->ocr_avail_sdio) |
716 | host->ocr_avail = host->ocr_avail_sdio; | 720 | host->ocr_avail = host->ocr_avail_sdio; |
@@ -783,12 +787,12 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
783 | pm_runtime_enable(&card->sdio_func[i]->dev); | 787 | pm_runtime_enable(&card->sdio_func[i]->dev); |
784 | } | 788 | } |
785 | 789 | ||
786 | mmc_release_host(host); | ||
787 | |||
788 | /* | 790 | /* |
789 | * First add the card to the driver model... | 791 | * First add the card to the driver model... |
790 | */ | 792 | */ |
793 | mmc_release_host(host); | ||
791 | err = mmc_add_card(host->card); | 794 | err = mmc_add_card(host->card); |
795 | mmc_claim_host(host); | ||
792 | if (err) | 796 | if (err) |
793 | goto remove_added; | 797 | goto remove_added; |
794 | 798 | ||
@@ -806,15 +810,17 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
806 | 810 | ||
807 | remove_added: | 811 | remove_added: |
808 | /* Remove without lock if the device has been added. */ | 812 | /* Remove without lock if the device has been added. */ |
813 | mmc_release_host(host); | ||
809 | mmc_sdio_remove(host); | 814 | mmc_sdio_remove(host); |
810 | mmc_claim_host(host); | 815 | mmc_claim_host(host); |
811 | remove: | 816 | remove: |
812 | /* And with lock if it hasn't been added. */ | 817 | /* And with lock if it hasn't been added. */ |
818 | mmc_release_host(host); | ||
813 | if (host->card) | 819 | if (host->card) |
814 | mmc_sdio_remove(host); | 820 | mmc_sdio_remove(host); |
821 | mmc_claim_host(host); | ||
815 | err: | 822 | err: |
816 | mmc_detach_bus(host); | 823 | mmc_detach_bus(host); |
817 | mmc_release_host(host); | ||
818 | 824 | ||
819 | printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", | 825 | printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", |
820 | mmc_hostname(host), err); | 826 | mmc_hostname(host), err); |