aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/bus.c23
-rw-r--r--drivers/mmc/core/core.c144
-rw-r--r--drivers/mmc/core/core.h22
-rw-r--r--drivers/mmc/core/host.c7
-rw-r--r--drivers/mmc/core/mmc.c26
-rw-r--r--drivers/mmc/core/mmc_ops.c2
-rw-r--r--drivers/mmc/core/mmc_ops.h2
-rw-r--r--drivers/mmc/core/sd.c36
-rw-r--r--drivers/mmc/core/sd_ops.c62
-rw-r--r--drivers/mmc/core/sd_ops.h3
10 files changed, 202 insertions, 125 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 348b566..fe0e785 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -209,10 +209,30 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host)
int mmc_add_card(struct mmc_card *card)
{
int ret;
+ const char *type;
snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
"%s:%04x", mmc_hostname(card->host), card->rca);
+ switch (card->type) {
+ case MMC_TYPE_MMC:
+ type = "MMC";
+ break;
+ case MMC_TYPE_SD:
+ type = "SD";
+ if (mmc_card_blockaddr(card))
+ type = "SDHC";
+ break;
+ default:
+ type = "?";
+ break;
+ }
+
+ printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+ mmc_hostname(card->host),
+ mmc_card_highspeed(card) ? "high speed " : "",
+ type, card->rca);
+
card->dev.uevent_suppress = 1;
ret = device_add(&card->dev);
@@ -243,6 +263,9 @@ int mmc_add_card(struct mmc_card *card)
void mmc_remove_card(struct mmc_card *card)
{
if (mmc_card_present(card)) {
+ printk(KERN_INFO "%s: card %04x removed\n",
+ mmc_hostname(card->host), card->rca);
+
if (card->host->bus_ops->sysfs_remove)
card->host->bus_ops->sysfs_remove(card->host, card);
device_del(&card->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b5d8a6d..bfd2ae5 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -68,32 +68,41 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
int err = cmd->error;
- pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
- mmc_hostname(host), cmd->opcode, err,
- mrq->data ? mrq->data->error : 0,
- mrq->stop ? mrq->stop->error : 0,
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
if (err && cmd->retries) {
+ pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+ mmc_hostname(host), cmd->opcode, err);
+
cmd->retries--;
cmd->error = 0;
host->ops->request(host, mrq);
- } else if (mrq->done) {
- mrq->done(mrq);
+ } else {
+ pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), cmd->opcode, err,
+ cmd->resp[0], cmd->resp[1],
+ cmd->resp[2], cmd->resp[3]);
+
+ if (mrq->data) {
+ pr_debug("%s: %d bytes transferred: %d\n",
+ mmc_hostname(host),
+ mrq->data->bytes_xfered, mrq->data->error);
+ }
+
+ if (mrq->stop) {
+ pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), mrq->stop->opcode,
+ mrq->stop->error,
+ mrq->stop->resp[0], mrq->stop->resp[1],
+ mrq->stop->resp[2], mrq->stop->resp[3]);
+ }
+
+ if (mrq->done)
+ mrq->done(mrq);
}
}
EXPORT_SYMBOL(mmc_request_done);
-/**
- * mmc_start_request - start a command on a host
- * @host: MMC host to start command on
- * @mrq: MMC request to start
- *
- * Queue a command on the specified host. We expect the
- * caller to be holding the host lock with interrupts disabled.
- */
-void
+static void
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
@@ -104,6 +113,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
+ if (mrq->data) {
+ pr_debug("%s: blksz %d blocks %d flags %08x "
+ "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_clks);
+ }
+
+ if (mrq->stop) {
+ pr_debug("%s: CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->stop->opcode,
+ mrq->stop->arg, mrq->stop->flags);
+ }
+
WARN_ON(!host->claimed);
mrq->cmd->error = 0;
@@ -133,14 +157,21 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
host->ops->request(host, mrq);
}
-EXPORT_SYMBOL(mmc_start_request);
-
static void mmc_wait_done(struct mmc_request *mrq)
{
complete(mrq->done_data);
}
-int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+/**
+ * mmc_wait_for_req - start a request and wait for completion
+ * @host: MMC host to start command
+ * @mrq: MMC request to start
+ *
+ * Start a new MMC custom command request for a host, and wait
+ * for the command to complete. Does not attempt to parse the
+ * response.
+ */
+void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
DECLARE_COMPLETION_ONSTACK(complete);
@@ -150,8 +181,6 @@ int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
mmc_start_request(host, mrq);
wait_for_completion(&complete);
-
- return 0;
}
EXPORT_SYMBOL(mmc_wait_for_req);
@@ -192,6 +221,9 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
* @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)
@@ -240,21 +272,18 @@ 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
- * @card: mmc card to claim host for
- *
- * Claim a host for a set of operations. If a valid card
- * is passed and this wasn't the last card selected, select
- * the card before returning.
*
- * Note: you should use mmc_card_claim_host or mmc_claim_host.
+ * Claim a host for a set of operations.
*/
void mmc_claim_host(struct mmc_host *host)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
+ might_sleep();
+
add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
while (1) {
@@ -433,6 +462,45 @@ static void mmc_power_off(struct mmc_host *host)
}
/*
+ * Cleanup when the last reference to the bus operator is dropped.
+ */
+void __mmc_release_bus(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(host->bus_refs);
+ BUG_ON(!host->bus_dead);
+
+ host->bus_ops = NULL;
+}
+
+/*
+ * Increase reference count of bus operator
+ */
+static inline void mmc_bus_get(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs++;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * Decrease reference count of bus operator and free it if
+ * it is the last reference.
+ */
+static inline void mmc_bus_put(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs--;
+ if ((host->bus_refs == 0) && host->bus_ops)
+ __mmc_release_bus(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
* Assign a mmc bus handler to a host. Only one bus handler may control a
* host at any given time.
*/
@@ -481,25 +549,15 @@ void mmc_detach_bus(struct mmc_host *host)
mmc_bus_put(host);
}
-/*
- * Cleanup when the last reference to the bus operator is dropped.
- */
-void __mmc_release_bus(struct mmc_host *host)
-{
- BUG_ON(!host);
- BUG_ON(host->bus_refs);
- BUG_ON(!host->bus_dead);
-
- host->bus_ops = NULL;
-}
-
/**
* mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state.
* @delay: optional delay to wait before detection (jiffies)
*
- * All we know is that card(s) have been inserted or removed
- * from the socket(s). We don't know which socket or cards.
+ * MMC drivers should call this when they detect a card has been
+ * inserted or removed. The MMC layer will confirm that any
+ * present card is still functional, and initialize any newly
+ * inserted.
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index ae006b3..bb2774a 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -27,28 +27,6 @@ struct mmc_bus_ops {
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);
-void __mmc_release_bus(struct mmc_host *host);
-
-static inline void mmc_bus_get(struct mmc_host *host)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs++;
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static inline void mmc_bus_put(struct mmc_host *host)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs--;
- if ((host->bus_refs == 0) && host->bus_ops)
- __mmc_release_bus(host);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 1433d95..6a7e298 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -93,6 +93,10 @@ EXPORT_SYMBOL(mmc_alloc_host);
/**
* mmc_add_host - initialise host hardware
* @host: mmc host
+ *
+ * Register the host with the driver model. The host must be
+ * prepared to start servicing requests before this function
+ * completes.
*/
int mmc_add_host(struct mmc_host *host)
{
@@ -126,7 +130,8 @@ EXPORT_SYMBOL(mmc_add_host);
* @host: mmc host
*
* Unregister and remove all cards associated with this host,
- * and power down the MMC bus.
+ * and power down the MMC bus. No new requests will be issued
+ * after this function has returned.
*/
void mmc_remove_host(struct mmc_host *host)
{
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 66f85bf..21d7f48 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc.c
+ * linux/drivers/mmc/core/mmc.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
@@ -100,7 +100,7 @@ static int mmc_decode_cid(struct mmc_card *card)
break;
default:
- printk("%s: card has unknown MMCA version %d\n",
+ printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
mmc_hostname(card->host), card->csd.mmca_vsn);
return -EINVAL;
}
@@ -123,7 +123,7 @@ static int mmc_decode_csd(struct mmc_card *card)
*/
csd_struct = UNSTUFF_BITS(resp, 126, 2);
if (csd_struct != 1 && csd_struct != 2) {
- printk("%s: unrecognised CSD structure version %d\n",
+ printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
return -EINVAL;
}
@@ -499,14 +499,17 @@ static void mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
-
err = mmc_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+
if (err != MMC_ERR_NONE) {
mmc_remove(host);
+
+ mmc_claim_host(host);
mmc_detach_bus(host);
+ mmc_release_host(host);
}
- mmc_release_host(host);
}
#else
@@ -553,8 +556,10 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
/*
* Can we support the voltage of the card?
*/
- if (!host->ocr)
+ if (!host->ocr) {
+ err = -EINVAL;
goto err;
+ }
/*
* Detect and init the card.
@@ -567,18 +572,21 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
err = mmc_add_card(host->card);
if (err)
- goto reclaim_host;
+ goto remove_card;
return 0;
-reclaim_host:
- mmc_claim_host(host);
+remove_card:
mmc_remove_card(host->card);
host->card = NULL;
+ mmc_claim_host(host);
err:
mmc_detach_bus(host);
mmc_release_host(host);
+ printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
+ mmc_hostname(host), err);
+
return 0;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 7dd720f..913e75f 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc_ops.h
+ * linux/drivers/mmc/core/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 7a481e8..76d09a9 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc_ops.h
+ * linux/drivers/mmc/core/mmc_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 1240684..1edc62b 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sd.c
+ * linux/drivers/mmc/core/sd.c
*
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
@@ -149,7 +149,7 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->write_partial = 0;
break;
default:
- printk("%s: unrecognised CSD structure version %d\n",
+ printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
return -EINVAL;
}
@@ -173,7 +173,7 @@ static int mmc_decode_scr(struct mmc_card *card)
scr_struct = UNSTUFF_BITS(resp, 60, 4);
if (scr_struct != 0) {
- printk("%s: unrecognised SCR structure version %d\n",
+ printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
mmc_hostname(card->host), scr_struct);
return -EINVAL;
}
@@ -206,9 +206,8 @@ static int mmc_read_switch(struct mmc_card *card)
status = kmalloc(64, GFP_KERNEL);
if (!status) {
- printk("%s: could not allocate a buffer for switch "
- "capabilities.\n",
- mmc_hostname(card->host));
+ printk(KERN_ERR "%s: could not allocate a buffer for "
+ "switch capabilities.\n", mmc_hostname(card->host));
return err;
}
@@ -254,9 +253,8 @@ static int mmc_switch_hs(struct mmc_card *card)
status = kmalloc(64, GFP_KERNEL);
if (!status) {
- printk("%s: could not allocate a buffer for switch "
- "capabilities.\n",
- mmc_hostname(card->host));
+ printk(KERN_ERR "%s: could not allocate a buffer for "
+ "switch capabilities.\n", mmc_hostname(card->host));
return err;
}
@@ -573,14 +571,17 @@ static void mmc_sd_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
-
err = mmc_sd_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
+
if (err != MMC_ERR_NONE) {
mmc_sd_remove(host);
+
+ mmc_claim_host(host);
mmc_detach_bus(host);
+ mmc_release_host(host);
}
- mmc_release_host(host);
}
#else
@@ -634,8 +635,10 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
/*
* Can we support the voltage(s) of the card(s)?
*/
- if (!host->ocr)
+ if (!host->ocr) {
+ err = -EINVAL;
goto err;
+ }
/*
* Detect and init the card.
@@ -648,18 +651,21 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
err = mmc_add_card(host->card);
if (err)
- goto reclaim_host;
+ goto remove_card;
return 0;
-reclaim_host:
- mmc_claim_host(host);
+remove_card:
mmc_remove_card(host->card);
host->card = NULL;
+ mmc_claim_host(host);
err:
mmc_detach_bus(host);
mmc_release_host(host);
+ printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
+ mmc_hostname(host), err);
+
return 0;
}
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 9697ce5..342f340 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sd_ops.h
+ * linux/drivers/mmc/core/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
@@ -21,11 +21,40 @@
#include "core.h"
#include "sd_ops.h"
+static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!host);
+ BUG_ON(card && (card->host != host));
+
+ cmd.opcode = MMC_APP_CMD;
+
+ if (card) {
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ } else {
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+ }
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ /* Check that card supported application commands */
+ if (!(cmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED;
+
+ return MMC_ERR_NONE;
+}
+
/**
* mmc_wait_for_app_cmd - start an application command and wait for
completion
* @host: MMC host to start command
- * @rca: RCA to send MMC_APP_CMD to
+ * @card: Card to send MMC_APP_CMD to
* @cmd: MMC command to start
* @retries: maximum number of retries
*
@@ -77,35 +106,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
-{
- int err;
- struct mmc_command cmd;
-
- BUG_ON(!host);
- BUG_ON(card && (card->host != host));
-
- cmd.opcode = MMC_APP_CMD;
-
- if (card) {
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
- }
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
- return err;
-
- /* Check that card supported application commands */
- if (!(cmd.resp[0] & R1_APP_CMD))
- return MMC_ERR_FAILED;
-
- return MMC_ERR_NONE;
-}
-
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
int err;
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 1240fdd..9742d8a 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/sd_ops.h
+ * linux/drivers/mmc/core/sd_ops.h
*
* Copyright 2006-2007 Pierre Ossman
*
@@ -12,7 +12,6 @@
#ifndef _MMC_SD_OPS_H
#define _MMC_SD_OPS_H
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);