aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/mmc.c25
-rw-r--r--drivers/mmc/mmc_block.c19
-rw-r--r--include/linux/mmc/card.h1
-rw-r--r--include/linux/mmc/protocol.h1
4 files changed, 38 insertions, 8 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 2ba46273496..f772df93a39 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1106,11 +1106,29 @@ static void mmc_process_ext_csds(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- printk("%s: unable to read EXT_CSD, performance "
- "might suffer.\n", mmc_hostname(card->host));
+ if (card->csd.capacity == (4096 * 512)) {
+ printk(KERN_ERR "%s: unable to read EXT_CSD "
+ "on a possible high capacity card. "
+ "Card will be ignored.\n",
+ mmc_hostname(card->host));
+ mmc_card_set_dead(card);
+ } else {
+ printk(KERN_WARNING "%s: unable to read "
+ "EXT_CSD, performance might "
+ "suffer.\n",
+ mmc_hostname(card->host));
+ }
continue;
}
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+ ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+ ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ if (card->ext_csd.sectors)
+ mmc_card_set_blockaddr(card);
+
switch (ext_csd[EXT_CSD_CARD_TYPE]) {
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
@@ -1499,7 +1517,8 @@ static void mmc_setup(struct mmc_host *host)
mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
}
} else {
- mmc_send_op_cond(host, host->ocr, NULL);
+ /* The extra bit indicates that we support high capacity */
+ mmc_send_op_cond(host, host->ocr | (1 << 30), NULL);
}
mmc_discover_cards(host);
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 95b0da6abe8..63fbde8756a 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -491,11 +491,20 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
- /*
- * The CSD capacity field is in units of read_blkbits.
- * set_capacity takes units of 512 bytes.
- */
- set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
+ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+ /*
+ * The EXT_CSD sector count is in number or 512 byte
+ * sectors.
+ */
+ set_capacity(md->disk, card->ext_csd.sectors);
+ } else {
+ /*
+ * The CSD capacity field is in units of read_blkbits.
+ * set_capacity takes units of 512 bytes.
+ */
+ set_capacity(md->disk,
+ card->csd.capacity << (card->csd.read_blkbits - 9));
+ }
return md;
err_putdisk:
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e45712acfac..5d9896c260a 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -41,6 +41,7 @@ struct mmc_csd {
struct mmc_ext_csd {
unsigned int hs_max_dtr;
+ unsigned int sectors;
};
struct sd_scr {
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
index c90b6768329..d740ab94fa2 100644
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -284,6 +284,7 @@ struct _mmc_csd {
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
/*
* EXT_CSD field definitions