]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/core/core.c
mmc: fix sdio timeout calculation
[linux-2.6-omap-h63xx.git] / drivers / mmc / core / core.c
index bfd2ae5bd669fe2a61307995832f2fd2bcb0c4c2..9d29bed820a1eef5da7b2238cc9a3701ac6da18a 100644 (file)
 #include "core.h"
 #include "bus.h"
 #include "host.h"
+#include "sdio_bus.h"
 
 #include "mmc_ops.h"
 #include "sd_ops.h"
+#include "sdio_ops.h"
 
 extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
 extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
 
 static struct workqueue_struct *workqueue;
 
@@ -118,7 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
                        "tsac %d ms nsac %d\n",
                        mmc_hostname(host), mrq->data->blksz,
                        mrq->data->blocks, mrq->data->flags,
-                       mrq->data->timeout_ns / 10000000,
+                       mrq->data->timeout_ns / 1000000,
                        mrq->data->timeout_clks);
        }
 
@@ -220,16 +223,23 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
  *     mmc_set_data_timeout - set the timeout for a data command
  *     @data: data phase for command
  *     @card: the MMC card associated with the data transfer
- *     @write: flag to differentiate reads from writes
  *
  *     Computes the data timeout parameters according to the
  *     correct algorithm given the card type.
  */
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
-                         int write)
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 {
        unsigned int mult;
 
+       /*
+        * SDIO cards only define an upper 1 s limit on access.
+        */
+       if (mmc_card_sdio(card)) {
+               data->timeout_ns = 1000000000;
+               data->timeout_clks = 0;
+               return;
+       }
+
        /*
         * SD cards use a 100 multiplier rather than 10
         */
@@ -239,7 +249,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
         * Scale up the multiplier (and therefore the timeout) by
         * the r2w factor for writes.
         */
-       if (write)
+       if (data->flags & MMC_DATA_WRITE)
                mult <<= card->csd.r2w_factor;
 
        data->timeout_ns = card->csd.tacc_ns * mult;
@@ -255,7 +265,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
                timeout_us += data->timeout_clks * 1000 /
                        (card->host->ios.clock / 1000);
 
-               if (write)
+               if (data->flags & MMC_DATA_WRITE)
                        limit_us = 250000;
                else
                        limit_us = 100000;
@@ -272,15 +282,20 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
 EXPORT_SYMBOL(mmc_set_data_timeout);
 
 /**
- *     mmc_claim_host - exclusively claim a host
+ *     __mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
+ *     @abort: whether or not the operation should be aborted
  *
- *     Claim a host for a set of operations.
+ *     Claim a host for a set of operations.  If @abort is non null and
+ *     dereference a non-zero value then this will return prematurely with
+ *     that non-zero value without acquiring the lock.  Returns zero
+ *     with the lock held otherwise.
  */
-void mmc_claim_host(struct mmc_host *host)
+int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
 {
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
+       int stop;
 
        might_sleep();
 
@@ -288,19 +303,24 @@ void mmc_claim_host(struct mmc_host *host)
        spin_lock_irqsave(&host->lock, flags);
        while (1) {
                set_current_state(TASK_UNINTERRUPTIBLE);
-               if (!host->claimed)
+               stop = abort ? atomic_read(abort) : 0;
+               if (stop || !host->claimed)
                        break;
                spin_unlock_irqrestore(&host->lock, flags);
                schedule();
                spin_lock_irqsave(&host->lock, flags);
        }
        set_current_state(TASK_RUNNING);
-       host->claimed = 1;
+       if (!stop)
+               host->claimed = 1;
+       else
+               wake_up(&host->wq);
        spin_unlock_irqrestore(&host->lock, flags);
        remove_wait_queue(&host->wq, &wait);
+       return stop;
 }
 
-EXPORT_SYMBOL(mmc_claim_host);
+EXPORT_SYMBOL(__mmc_claim_host);
 
 /**
  *     mmc_release_host - release a host
@@ -597,24 +617,38 @@ void mmc_rescan(struct work_struct *work)
 
                mmc_send_if_cond(host, host->ocr_avail);
 
+               /*
+                * First we search for SDIO...
+                */
+               err = mmc_send_io_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_sdio(host, ocr))
+                               mmc_power_off(host);
+                       return;
+               }
+
+               /*
+                * ...then normal SD...
+                */
                err = mmc_send_app_op_cond(host, 0, &ocr);
-               if (err == MMC_ERR_NONE) {
+               if (!err) {
                        if (mmc_attach_sd(host, ocr))
                                mmc_power_off(host);
-               } else {
-                       /*
-                        * If we fail to detect any SD cards then try
-                        * searching for MMC cards.
-                        */
-                       err = mmc_send_op_cond(host, 0, &ocr);
-                       if (err == MMC_ERR_NONE) {
-                               if (mmc_attach_mmc(host, ocr))
-                                       mmc_power_off(host);
-                       } else {
+                       return;
+               }
+
+               /*
+                * ...and finally MMC.
+                */
+               err = mmc_send_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_mmc(host, ocr))
                                mmc_power_off(host);
-                               mmc_release_host(host);
-                       }
+                       return;
                }
+
+               mmc_release_host(host);
+               mmc_power_off(host);
        } else {
                if (host->bus_ops->detect && !host->bus_dead)
                        host->bus_ops->detect(host);
@@ -725,22 +759,38 @@ static int __init mmc_init(void)
                return -ENOMEM;
 
        ret = mmc_register_bus();
-       if (ret == 0) {
-               ret = mmc_register_host_class();
-               if (ret)
-                       mmc_unregister_bus();
-       }
+       if (ret)
+               goto destroy_workqueue;
+
+       ret = mmc_register_host_class();
+       if (ret)
+               goto unregister_bus;
+
+       ret = sdio_register_bus();
+       if (ret)
+               goto unregister_host_class;
+
+       return 0;
+
+unregister_host_class:
+       mmc_unregister_host_class();
+unregister_bus:
+       mmc_unregister_bus();
+destroy_workqueue:
+       destroy_workqueue(workqueue);
+
        return ret;
 }
 
 static void __exit mmc_exit(void)
 {
+       sdio_unregister_bus();
        mmc_unregister_host_class();
        mmc_unregister_bus();
        destroy_workqueue(workqueue);
 }
 
-module_init(mmc_init);
+subsys_initcall(mmc_init);
 module_exit(mmc_exit);
 
 MODULE_LICENSE("GPL");