]> err.no Git - linux-2.6/blobdiff - drivers/mmc/core/core.c
mmc: properly iterate over sg list in debug check
[linux-2.6] / drivers / mmc / core / core.c
index 01ced4c5a61d45016234654c9e0cf3313ad0ff3d..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
@@ -121,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",
@@ -156,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
 
@@ -294,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
@@ -638,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);
@@ -652,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;
                }
 
                /*
@@ -662,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;
                }
 
                /*
@@ -672,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);
@@ -683,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)