summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c13
-rw-r--r--drivers/mmc/mmc.c921
2 files changed, 398 insertions, 536 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8eba037..8a84e4d 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -226,8 +226,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
struct mmc_blk_request brq;
int ret = 1, sg_pos, data_size;
- if (mmc_card_claim_host(card))
- goto flush_queue;
+ mmc_claim_host(card->host);
do {
struct mmc_command cmd;
@@ -357,7 +356,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
} while (ret);
- mmc_card_release_host(card);
+ mmc_release_host(card->host);
return 1;
@@ -393,9 +392,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
-flush_queue:
-
- mmc_card_release_host(card);
+ mmc_release_host(card->host);
spin_lock_irq(&md->lock);
while (ret) {
@@ -526,12 +523,12 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
if (mmc_card_blockaddr(card))
return 0;
- mmc_card_claim_host(card);
+ mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
- mmc_card_release_host(card);
+ mmc_release_host(card->host);
if (err) {
printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 94c0472..3f50b88 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2005-2007 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
@@ -316,8 +316,6 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
}
EXPORT_SYMBOL(mmc_set_data_timeout);
-static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
-
/**
* __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
@@ -329,11 +327,10 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
*
* Note: you should use mmc_card_claim_host or mmc_claim_host.
*/
-int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
+void mmc_claim_host(struct mmc_host *host)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
- int err = 0;
add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
@@ -349,17 +346,9 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
-
- if (card != (void *)-1) {
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE)
- return err;
- }
-
- return err;
}
-EXPORT_SYMBOL(__mmc_claim_host);
+EXPORT_SYMBOL(mmc_claim_host);
/**
* mmc_release_host - release a host
@@ -396,23 +385,18 @@ static inline void mmc_set_ios(struct mmc_host *host)
host->ops->set_ios(host, ios);
}
-static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+static int mmc_select_card(struct mmc_card *card)
{
int err;
struct mmc_command cmd;
- BUG_ON(!host->claimed);
-
- if (host->card_selected == card)
- return MMC_ERR_NONE;
-
- host->card_selected = card;
+ BUG_ON(!card->host->claimed);
cmd.opcode = MMC_SELECT_CARD;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE)
return err;
@@ -426,49 +410,24 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
* wider version.
*/
if (mmc_card_sd(card) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) &&
+ (card->host->caps & MMC_CAP_4_BIT_DATA)) {
- /*
- * Default bus width is 1 bit.
- */
- host->ios.bus_width = MMC_BUS_WIDTH_1;
-
- if (host->caps & MMC_CAP_4_BIT_DATA) {
- struct mmc_command cmd;
- cmd.opcode = SD_APP_SET_BUS_WIDTH;
- cmd.arg = SD_BUS_WIDTH_4;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
- CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- return err;
-
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- }
- }
-
- mmc_set_ios(host);
-
- return MMC_ERR_NONE;
-}
-
-/*
- * Ensure that no card is selected.
- */
-static void mmc_deselect_cards(struct mmc_host *host)
-{
- struct mmc_command cmd;
-
- if (host->card_selected) {
- host->card_selected = NULL;
+ struct mmc_command cmd;
+ cmd.opcode = SD_APP_SET_BUS_WIDTH;
+ cmd.arg = SD_BUS_WIDTH_4;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
+ err = mmc_wait_for_app_cmd(card->host, card->rca,
+ &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
- mmc_wait_for_cmd(host, &cmd, 0);
+ card->host->ios.bus_width = MMC_BUS_WIDTH_4;
+ mmc_set_ios(card->host);
}
+
+ return MMC_ERR_NONE;
}
@@ -732,27 +691,12 @@ static void mmc_decode_scr(struct mmc_card *card)
}
/*
- * Locate a MMC card on this MMC host given a raw CID.
- */
-static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid)
-{
- struct mmc_card *card;
-
- list_for_each_entry(card, &host->cards, node) {
- if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0)
- return card;
- }
- return NULL;
-}
-
-/*
- * Allocate a new MMC card, and assign a unique RCA.
+ * Allocate a new MMC card
*/
static struct mmc_card *
-mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
+mmc_alloc_card(struct mmc_host *host, u32 *raw_cid)
{
- struct mmc_card *card, *c;
- unsigned int rca = *frca;
+ struct mmc_card *card;
card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
if (!card)
@@ -761,17 +705,6 @@ mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
mmc_init_card(card, host);
memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));
- again:
- list_for_each_entry(c, &host->cards, node)
- if (c->rca == rca) {
- rca++;
- goto again;
- }
-
- card->rca = rca;
-
- *frca = rca;
-
return card;
}
@@ -937,128 +870,128 @@ static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
}
/*
- * Discover cards by requesting their CID. If this command
- * times out, it is not an error; there are no further cards
- * to be discovered. Add new cards to the list.
+ * Discover the card by requesting its CID.
*
- * Create a mmc_card entry for each discovered card, assigning
+ * Create a mmc_card entry for the discovered card, assigning
* it an RCA, and save the raw CID for decoding later.
*/
-static void mmc_discover_cards(struct mmc_host *host)
+static void mmc_discover_card(struct mmc_host *host)
{
- struct mmc_card *card;
- unsigned int first_rca = 1, err;
+ unsigned int err;
- while (1) {
- struct mmc_command cmd;
+ struct mmc_command cmd;
- cmd.opcode = MMC_ALL_SEND_CID;
+ BUG_ON(host->card);
+
+ cmd.opcode = MMC_ALL_SEND_CID;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err == MMC_ERR_TIMEOUT) {
+ err = MMC_ERR_NONE;
+ return;
+ }
+ if (err != MMC_ERR_NONE) {
+ printk(KERN_ERR "%s: error requesting CID: %d\n",
+ mmc_hostname(host), err);
+ return;
+ }
+
+ host->card = mmc_alloc_card(host, cmd.resp);
+ if (IS_ERR(host->card)) {
+ err = PTR_ERR(host->card);
+ host->card = NULL;
+ return;
+ }
+
+ if (host->mode == MMC_MODE_SD) {
+ host->card->type = MMC_TYPE_SD;
+
+ cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_TIMEOUT) {
- err = MMC_ERR_NONE;
- break;
- }
- if (err != MMC_ERR_NONE) {
- printk(KERN_ERR "%s: error requesting CID: %d\n",
- mmc_hostname(host), err);
- break;
- }
-
- card = mmc_find_card(host, cmd.resp);
- if (!card) {
- card = mmc_alloc_card(host, cmd.resp, &first_rca);
- if (IS_ERR(card)) {
- err = PTR_ERR(card);
- break;
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(host->card);
+ else {
+ host->card->rca = cmd.resp[0] >> 16;
+
+ if (!host->ops->get_ro) {
+ printk(KERN_WARNING "%s: host does not "
+ "support reading read-only "
+ "switch. assuming write-enable.\n",
+ mmc_hostname(host));
+ } else {
+ if (host->ops->get_ro(host))
+ mmc_card_set_readonly(host->card);
}
- list_add(&card->node, &host->cards);
}
+ } else {
+ host->card->type = MMC_TYPE_MMC;
+ host->card->rca = 1;
- card->state &= ~MMC_STATE_DEAD;
-
- if (host->mode == MMC_MODE_SD) {
- card->type = MMC_TYPE_SD;
-
- cmd.opcode = SD_SEND_RELATIVE_ADDR;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(card);
- else {
- card->rca = cmd.resp[0] >> 16;
-
- if (!host->ops->get_ro) {
- printk(KERN_WARNING "%s: host does not "
- "support reading read-only "
- "switch. assuming write-enable.\n",
- mmc_hostname(host));
- } else {
- if (host->ops->get_ro(host))
- mmc_card_set_readonly(card);
- }
- }
- } else {
- card->type = MMC_TYPE_MMC;
- cmd.opcode = MMC_SET_RELATIVE_ADDR;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(card);
- }
+ cmd.opcode = MMC_SET_RELATIVE_ADDR;
+ cmd.arg = host->card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(host->card);
}
}
-static void mmc_read_csds(struct mmc_host *host)
+static void mmc_read_csd(struct mmc_host *host)
{
- struct mmc_card *card;
-
- list_for_each_entry(card, &host->cards, node) {
- struct mmc_command cmd;
- int err;
+ struct mmc_command cmd;
+ int err;
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
+ if (!host->card)
+ return;
+ if (mmc_card_dead(host->card))
+ return;
- cmd.opcode = MMC_SEND_CSD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
+ cmd.opcode = MMC_SEND_CSD;
+ cmd.arg = host->card->rca << 16;
+ cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(host->card);
+ return;
+ }
- memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd));
+ memcpy(host->card->raw_csd, cmd.resp, sizeof(host->card->raw_csd));
- mmc_decode_csd(card);
- mmc_decode_cid(card);
- }
+ mmc_decode_csd(host->card);
+ mmc_decode_cid(host->card);
}
-static void mmc_process_ext_csds(struct mmc_host *host)
+static void mmc_process_ext_csd(struct mmc_host *host)
{
int err;
- struct mmc_card *card;
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
+ u8 *ext_csd;
struct scatterlist sg;
+ if (!host->card)
+ return;
+ if (mmc_card_dead(host->card))
+ return;
+ if (mmc_card_sd(host->card))
+ return;
+ if (host->card->csd.mmca_vsn < CSD_SPEC_VER_4)
+ return;
+
/*
* As the ext_csd is so large and mostly unused, we don't store the
* raw block in mmc_card.
*/
- u8 *ext_csd;
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
printk("%s: could not allocate a buffer to receive the ext_csd."
@@ -1067,211 +1000,184 @@ static void mmc_process_ext_csds(struct mmc_host *host)
return;
}
- list_for_each_entry(card, &host->cards, node) {
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
- if (mmc_card_sd(card))
- continue;
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- continue;
-
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = MMC_SEND_EXT_CSD;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.opcode = MMC_SEND_EXT_CSD;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- memset(&data, 0, sizeof(struct mmc_data));
+ memset(&data, 0, sizeof(struct mmc_data));
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, host->card, 0);
- data.blksz = 512;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
+ data.blksz = 512;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
- memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&mrq, 0, sizeof(struct mmc_request));
- mrq.cmd = &cmd;
- mrq.data = &data;
+ mrq.cmd = &cmd;
+ mrq.data = &data;
- sg_init_one(&sg, ext_csd, 512);
+ sg_init_one(&sg, ext_csd, 512);
- mmc_wait_for_req(host, &mrq);
+ mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- 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;
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+ if (host->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(host));
+ mmc_card_set_dead(host->card);
+ } else {
+ printk(KERN_WARNING "%s: unable to read "
+ "EXT_CSD, performance might "
+ "suffer.\n",
+ mmc_hostname(host));
}
+ goto out;
+ }
- 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);
+ host->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 (host->card->ext_csd.sectors)
+ mmc_card_set_blockaddr(host->card);
+
+ switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+ case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
+ host->card->ext_csd.hs_max_dtr = 52000000;
+ break;
+ case EXT_CSD_CARD_TYPE_26:
+ host->card->ext_csd.hs_max_dtr = 26000000;
+ break;
+ default:
+ /* MMC v4 spec says this cannot happen */
+ printk("%s: card is mmc v4 but doesn't support "
+ "any high-speed modes.\n",
+ mmc_hostname(host));
+ goto out;
+ }
- 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;
- break;
- case EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 26000000;
- break;
- default:
- /* MMC v4 spec says this cannot happen */
- printk("%s: card is mmc v4 but doesn't support "
- "any high-speed modes.\n",
- mmc_hostname(card->host));
- continue;
- }
+ if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
+ /* Activate highspeed support. */
+ cmd.opcode = MMC_SWITCH;
+ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_HS_TIMING << 16) |
+ (1 << 8) |
+ EXT_CSD_CMD_SET_NORMAL;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
- /* Activate highspeed support. */
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_HS_TIMING << 16) |
- (1 << 8) |
- EXT_CSD_CMD_SET_NORMAL;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to mmc v4 "
- "high-speed mode.\n",
- mmc_hostname(card->host));
- continue;
- }
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ printk("%s: failed to switch card to mmc v4 "
+ "high-speed mode.\n",
+ mmc_hostname(host));
+ goto out;
+ }
- mmc_card_set_highspeed(card);
+ mmc_card_set_highspeed(host->card);
- host->ios.timing = MMC_TIMING_MMC_HS;
- mmc_set_ios(host);
- }
+ host->ios.timing = MMC_TIMING_MMC_HS;
+ mmc_set_ios(host);
+ }
- /* Check for host support for wide-bus modes. */
- if (host->caps & MMC_CAP_4_BIT_DATA) {
- /* Activate 4-bit support. */
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_BUS_WIDTH << 16) |
- (EXT_CSD_BUS_WIDTH_4 << 8) |
- EXT_CSD_CMD_SET_NORMAL;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to "
- "mmc v4 4-bit bus mode.\n",
- mmc_hostname(card->host));
- continue;
- }
+ /* Check for host support for wide-bus modes. */
+ if (host->caps & MMC_CAP_4_BIT_DATA) {
+ /* Activate 4-bit support. */
+ cmd.opcode = MMC_SWITCH;
+ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_BUS_WIDTH << 16) |
+ (EXT_CSD_BUS_WIDTH_4 << 8) |
+ EXT_CSD_CMD_SET_NORMAL;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- mmc_set_ios(host);
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ printk("%s: failed to switch card to "
+ "mmc v4 4-bit bus mode.\n",
+ mmc_hostname(host));
+ goto out;
}
+
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ mmc_set_ios(host);
}
+out:
kfree(ext_csd);
-
- mmc_deselect_cards(host);
}
-static void mmc_read_scrs(struct mmc_host *host)
+static void mmc_read_scr(struct mmc_host *host)
{
int err;
- struct mmc_card *card;
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
struct scatterlist sg;
- list_for_each_entry(card, &host->cards, node) {
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
- if (!mmc_card_sd(card))
- continue;
-
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = MMC_APP_CMD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ if (!host->card)
+ return;
+ if (mmc_card_dead(host->card))
+ return;
+ if (!mmc_card_sd(host->card))
+ return;
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
- mmc_card_set_dead(card);
- continue;
- }
+ memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = host->card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- cmd.opcode = SD_APP_SEND_SCR;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+ mmc_card_set_dead(host->card);
+ return;
+ }
- memset(&data, 0, sizeof(struct mmc_data));
+ memset(&cmd, 0, sizeof(struct mmc_command));
- mmc_set_data_timeout(&data, card, 0);
+ cmd.opcode = SD_APP_SEND_SCR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- data.blksz = 1 << 3;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
+ memset(&data, 0, sizeof(struct mmc_data));
- memset(&mrq, 0, sizeof(struct mmc_request));
+ mmc_set_data_timeout(&data, host->card, 0);
- mrq.cmd = &cmd;
- mrq.data = &data;
+ data.blksz = 1 << 3;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
- sg_init_one(&sg, (u8*)card->raw_scr, 8);
+ memset(&mrq, 0, sizeof(struct mmc_request));
- mmc_wait_for_req(host, &mrq);
+ mrq.cmd = &cmd;
+ mrq.data = &data;
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
+ sg_init_one(&sg, (u8*)host->card->raw_scr, 8);
- card->raw_scr[0] = ntohl(card->raw_scr[0]);
- card->raw_scr[1] = ntohl(card->raw_scr[1]);
+ mmc_wait_for_req(host, &mrq);
- mmc_decode_scr(card);
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+ mmc_card_set_dead(host->card);
+ return;
}
- mmc_deselect_cards(host);
+ host->card->raw_scr[0] = ntohl(host->card->raw_scr[0]);
+ host->card->raw_scr[1] = ntohl(host->card->raw_scr[1]);
+
+ mmc_decode_scr(host->card);
}
static void mmc_read_switch_caps(struct mmc_host *host)
{
- int err;
- struct mmc_card *card;
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
@@ -1281,6 +1187,15 @@ static void mmc_read_switch_caps(struct mmc_host *host)
if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
return;
+ if (!host->card)
+ return;
+ if (mmc_card_dead(host->card))
+ return;
+ if (!mmc_card_sd(host->card))
+ return;
+ if (host->card->scr.sda_vsn < SCR_SPEC_VER_1)
+ return;
+
status = kmalloc(64, GFP_KERNEL);
if (!status) {
printk(KERN_WARNING "%s: Unable to allocate buffer for "
@@ -1289,116 +1204,98 @@ static void mmc_read_switch_caps(struct mmc_host *host)
return;
}
- list_for_each_entry(card, &host->cards, node) {
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
- if (!mmc_card_sd(card))
- continue;
- if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- continue;
-
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = SD_SWITCH;
- cmd.arg = 0x00FFFFF1;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.opcode = SD_SWITCH;
+ cmd.arg = 0x00FFFFF1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- memset(&data, 0, sizeof(struct mmc_data));
+ memset(&data, 0, sizeof(struct mmc_data));
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, host->card, 0);
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
+ data.blksz = 64;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
- memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&mrq, 0, sizeof(struct mmc_request));
- mrq.cmd = &cmd;
- mrq.data = &data;
+ mrq.cmd = &cmd;
+ mrq.data = &data;
- sg_init_one(&sg, status, 64);
+ sg_init_one(&sg, status, 64);
- mmc_wait_for_req(host, &mrq);
+ mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- printk("%s: unable to read switch capabilities, "
- "performance might suffer.\n",
- mmc_hostname(card->host));
- continue;
- }
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
+ printk("%s: unable to read switch capabilities, "
+ "performance might suffer.\n",
+ mmc_hostname(host));
+ goto out;
+ }
- if (status[13] & 0x02)
- card->sw_caps.hs_max_dtr = 50000000;
+ if (status[13] & 0x02)
+ host->card->sw_caps.hs_max_dtr = 50000000;
- memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = SD_SWITCH;
- cmd.arg = 0x80FFFFF1;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.opcode = SD_SWITCH;
+ cmd.arg = 0x80FFFFF1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- memset(&data, 0, sizeof(struct mmc_data));
+ memset(&data, 0, sizeof(struct mmc_data));
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, host->card, 0);
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
+ data.blksz = 64;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
- memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&mrq, 0, sizeof(struct mmc_request));
- mrq.cmd = &cmd;
- mrq.data = &data;
+ mrq.cmd = &cmd;
+ mrq.data = &data;
- sg_init_one(&sg, status, 64);
+ sg_init_one(&sg, status, 64);
- mmc_wait_for_req(host, &mrq);
+ mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
- (status[16] & 0xF) != 1) {
- printk(KERN_WARNING "%s: Problem switching card "
- "into high-speed mode!\n",
- mmc_hostname(host));
- continue;
- }
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
+ (status[16] & 0xF) != 1) {
+ printk(KERN_WARNING "%s: Problem switching card "
+ "into high-speed mode!\n",
+ mmc_hostname(host));
+ goto out;
+ }
- mmc_card_set_highspeed(card);
+ mmc_card_set_highspeed(host->card);
- host->ios.timing = MMC_TIMING_SD_HS;
- mmc_set_ios(host);
- }
+ host->ios.timing = MMC_TIMING_SD_HS;
+ mmc_set_ios(host);
+out:
kfree(status);
-
- mmc_deselect_cards(host);
}
static unsigned int mmc_calculate_clock(struct mmc_host *host)
{
- struct mmc_card *card;
unsigned int max_dtr = host->f_max;
- list_for_each_entry(card, &host->cards, node)
- if (!mmc_card_dead(card)) {
- if (mmc_card_highspeed(card) && mmc_card_sd(card)) {
- if (max_dtr > card->sw_caps.hs_max_dtr)
- max_dtr = card->sw_caps.hs_max_dtr;
- } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {
- if (max_dtr > card->ext_csd.hs_max_dtr)
- max_dtr = card->ext_csd.hs_max_dtr;
- } else if (max_dtr > card->csd.max_dtr) {
- max_dtr = card->csd.max_dtr;
- }
+ if (host->card && !mmc_card_dead(host->card)) {
+ if (mmc_card_highspeed(host->card) && mmc_card_sd(host->card)) {
+ if (max_dtr > host->card->sw_caps.hs_max_dtr)
+ max_dtr = host->card->sw_caps.hs_max_dtr;
+ } else if (mmc_card_highspeed(host->card) && !mmc_card_sd(host->card)) {
+ if (max_dtr > host->card->ext_csd.hs_max_dtr)
+ max_dtr = host->card->ext_csd.hs_max_dtr;
+ } else if (max_dtr > host->card->csd.max_dtr) {
+ max_dtr = host->card->csd.max_dtr;
}
+ }
pr_debug("%s: selected %d.%03dMHz transfer rate\n",
mmc_hostname(host),
@@ -1415,92 +1312,66 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host)
* A request for status does not cause a state change in data
* transfer mode.
*/
-static void mmc_check_cards(struct mmc_host *host)
+static void mmc_check_card(struct mmc_card *card)
{
- struct list_head *l, *n;
-
- mmc_deselect_cards(host);
+ struct mmc_command cmd;
+ int err;
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
- struct mmc_command cmd;
- int err;
+ BUG_ON(!card);
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_NONE)
- continue;
+ err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES);
+ if (err == MMC_ERR_NONE)
+ return;
- mmc_card_set_dead(card);
- }
+ mmc_card_set_dead(card);
}
static void mmc_setup(struct mmc_host *host)
{
- if (host->ios.power_mode != MMC_POWER_ON) {
- int err;
- u32 ocr;
-
- host->mode = MMC_MODE_SD;
-
- mmc_power_up(host);
- mmc_idle_cards(host);
+ int err;
+ u32 ocr;
- err = mmc_send_if_cond(host, host->ocr_avail, NULL);
- if (err != MMC_ERR_NONE) {
- return;
- }
- err = mmc_send_app_op_cond(host, 0, &ocr);
+ host->mode = MMC_MODE_SD;
- /*
- * If we fail to detect any SD cards then try
- * searching for MMC cards.
- */
- if (err != MMC_ERR_NONE) {
- host->mode = MMC_MODE_MMC;
-
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err != MMC_ERR_NONE)
- return;
- }
+ mmc_power_up(host);
+ mmc_idle_cards(host);
- host->ocr = mmc_select_voltage(host, ocr);
+ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+ if (err != MMC_ERR_NONE) {
+ return;
+ }
+ err = mmc_send_app_op_cond(host, 0, &ocr);
- /*
- * Since we're changing the OCR value, we seem to
- * need to tell some cards to go back to the idle
- * state. We wait 1ms to give cards time to
- * respond.
- */
- if (host->ocr)
- mmc_idle_cards(host);
- } else {
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.clock = host->f_min;
- mmc_set_ios(host);
+ /*
+ * If we fail to detect any SD cards then try
+ * searching for MMC cards.
+ */
+ if (err != MMC_ERR_NONE) {
+ host->mode = MMC_MODE_MMC;
- /*
- * We should remember the OCR mask from the existing
- * cards, and detect the new cards OCR mask, combine
- * the two and re-select the VDD. However, if we do
- * change VDD, we should do an idle, and then do a
- * full re-initialisation. We would need to notify
- * drivers so that they can re-setup the cards as
- * well, while keeping their queues at bay.
- *
- * For the moment, we take the easy way out - if the
- * new cards don't like our currently selected VDD,
- * they drop off the bus.
- */
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (err != MMC_ERR_NONE)
+ return;
}
+ host->ocr = mmc_select_voltage(host, ocr);
+
if (host->ocr == 0)
return;
/*
+ * Since we're changing the OCR value, we seem to
+ * need to tell some cards to go back to the idle
+ * state. We wait 1ms to give cards time to
+ * respond.
+ */
+ mmc_idle_cards(host);
+
+ /*
* Send the selected OCR multiple times... until the cards
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
@@ -1522,7 +1393,7 @@ static void mmc_setup(struct mmc_host *host)
mmc_send_op_cond(host, host->ocr | (1 << 30), NULL);
}
- mmc_discover_cards(host);
+ mmc_discover_card(host);
/*
* Ok, now switch to push-pull mode.
@@ -1530,13 +1401,19 @@ static void mmc_setup(struct mmc_host *host)
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
mmc_set_ios(host);
- mmc_read_csds(host);
+ mmc_read_csd(host);
+
+ if (host->card && !mmc_card_dead(host->card)) {
+ err = mmc_select_card(host->card);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(host->card);
+ }
if (host->mode == MMC_MODE_SD) {
- mmc_read_scrs(host);
+ mmc_read_scr(host);
mmc_read_switch_caps(host);
} else
- mmc_process_ext_csds(host);
+ mmc_process_ext_csd(host);
}
@@ -1566,31 +1443,29 @@ static void mmc_rescan(struct work_struct *work)
{
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
- struct list_head *l, *n;
- unsigned char power_mode;
mmc_claim_host(host);
/*
- * Check for removed cards and newly inserted ones. We check for
+ * Check for removed card and newly inserted ones. We check for
* removed cards first so we can intelligently re-select the VDD.
*/
- power_mode = host->ios.power_mode;
- if (power_mode == MMC_POWER_ON)
- mmc_check_cards(host);
+ if (host->card) {
+ mmc_check_card(host->card);
- mmc_setup(host);
+ mmc_release_host(host);
- /*
- * Some broken cards process CMD1 even in stand-by state. There is
- * no reply, but an ILLEGAL_COMMAND error is cached and returned
- * after next command. We poll for card status here to clear any
- * possibly pending error.
- */
- if (power_mode == MMC_POWER_ON)
- mmc_check_cards(host);
+ if (mmc_card_dead(host->card)) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+ }
+
+ goto out;
+ }
- if (!list_empty(&host->cards)) {
+ mmc_setup(host);
+
+ if (host->card && !mmc_card_dead(host->card)) {
/*
* (Re-)calculate the fastest clock rate which the
* attached cards and the host support.
@@ -1601,31 +1476,28 @@ static void mmc_rescan(struct work_struct *work)
mmc_release_host(host);
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
-
- /*
- * If this is a new and good card, register it.
- */
- if (!mmc_card_present(card) && !mmc_card_dead(card)) {
- if (mmc_register_card(card))
- mmc_card_set_dead(card);
- }
+ /*
+ * If this is a new and good card, register it.
+ */
+ if (host->card && !mmc_card_dead(host->card)) {
+ if (mmc_register_card(host->card))
+ mmc_card_set_dead(host->card);
+ }
- /*
- * If this card is dead, destroy it.
- */
- if (mmc_card_dead(card)) {
- list_del(&card->node);
- mmc_remove_card(card);
- }
+ /*
+ * If this card is dead, destroy it.
+ */
+ if (host->card && mmc_card_dead(host->card)) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
}
+out:
/*
* If we discover that there are no cards on the
* bus, turn off the clock and power down.
*/
- if (list_empty(&host->cards))
+ if (!host->card)
mmc_power_off(host);
}
@@ -1645,7 +1517,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
if (host) {
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
- INIT_LIST_HEAD(&host->cards);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
/*
@@ -1694,8 +1565,6 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
- struct list_head *l, *n;
-
#ifdef CONFIG_MMC_DEBUG
mmc_claim_host(host);
host->removed = 1;
@@ -1704,10 +1573,9 @@ void mmc_remove_host(struct mmc_host *host)
mmc_flush_scheduled_work();
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
-
- mmc_remove_card(card);
+ if (host->card) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
}
mmc_power_off(host);
@@ -1738,14 +1606,11 @@ EXPORT_SYMBOL(mmc_free_host);
*/
int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
{
- struct list_head *l, *n;
-
mmc_flush_scheduled_work();
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
-
- mmc_remove_card(card);
+ if (host->card) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
}
mmc_power_off(host);
OpenPOWER on IntegriCloud