]> err.no Git - linux-2.6/blobdiff - drivers/mmc/core/core.c
Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / drivers / mmc / core / core.c
index ab91b02b2bffdfa2b4f784b43c482815e1734fc5..044d84eeed7c75f2775b27d3cb6b55630c08f688 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
  *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
 #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;
 
 /*
@@ -125,6 +121,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 {
 #ifdef CONFIG_MMC_DEBUG
        unsigned int i, sz;
+       struct scatterlist *sg;
 #endif
 
        pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
@@ -160,8 +157,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 
 #ifdef CONFIG_MMC_DEBUG
                sz = 0;
-               for (i = 0;i < mrq->data->sg_len;i++)
-                       sz += mrq->data->sg[i].length;
+               for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
+                       sz += sg->length;
                BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
 #endif
 
@@ -298,6 +295,33 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_set_data_timeout);
 
+/**
+ *     mmc_align_data_size - pads a transfer size to a more optimal value
+ *     @card: the MMC card associated with the data transfer
+ *     @sz: original transfer size
+ *
+ *     Pads the original data size with a number of extra bytes in
+ *     order to avoid controller bugs and/or performance hits
+ *     (e.g. some controllers revert to PIO for certain sizes).
+ *
+ *     Returns the improved size, which might be unmodified.
+ *
+ *     Note that this function is only relevant when issuing a
+ *     single scatter gather entry.
+ */
+unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
+{
+       /*
+        * FIXME: We don't have a system for the controller to tell
+        * the core about its problems yet, so for now we just 32-bit
+        * align the size.
+        */
+       sz = ((sz + 3) / 4) * 4;
+
+       return sz;
+}
+EXPORT_SYMBOL(mmc_align_data_size);
+
 /**
  *     __mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
@@ -642,6 +666,9 @@ void mmc_rescan(struct work_struct *work)
                 */
                mmc_bus_put(host);
 
+               if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+                       goto out;
+
                mmc_claim_host(host);
 
                mmc_power_up(host);
@@ -656,7 +683,7 @@ void mmc_rescan(struct work_struct *work)
                if (!err) {
                        if (mmc_attach_sdio(host, ocr))
                                mmc_power_off(host);
-                       return;
+                       goto out;
                }
 
                /*
@@ -666,7 +693,7 @@ void mmc_rescan(struct work_struct *work)
                if (!err) {
                        if (mmc_attach_sd(host, ocr))
                                mmc_power_off(host);
-                       return;
+                       goto out;
                }
 
                /*
@@ -676,7 +703,7 @@ void mmc_rescan(struct work_struct *work)
                if (!err) {
                        if (mmc_attach_mmc(host, ocr))
                                mmc_power_off(host);
-                       return;
+                       goto out;
                }
 
                mmc_release_host(host);
@@ -687,6 +714,9 @@ void mmc_rescan(struct work_struct *work)
 
                mmc_bus_put(host);
        }
+out:
+       if (host->caps & MMC_CAP_NEEDS_POLL)
+               mmc_schedule_delayed_work(&host->detect, HZ);
 }
 
 void mmc_start_host(struct mmc_host *host)