summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/block.c35
-rw-r--r--drivers/mmc/card/queue.c35
-rw-r--r--drivers/mmc/card/queue.h8
-rw-r--r--drivers/mmc/core/sd.c41
-rw-r--r--drivers/mmc/host/at91_mci.c5
-rw-r--r--drivers/mmc/host/au1xmmc.c38
-rw-r--r--drivers/mmc/host/omap.c24
-rw-r--r--drivers/mmc/host/pxamci.c18
-rw-r--r--drivers/mmc/host/sdhci.c9
9 files changed, 83 insertions, 130 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index d24ab234394c..540ff4bea54c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -45,8 +45,6 @@
*/
#define MMC_SHIFT 3
-static int major;
-
/*
* There is one mmc_blk_data per slot.
*/
@@ -137,23 +135,6 @@ struct mmc_blk_request {
struct mmc_data data;
};
-static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
-{
- struct mmc_blk_data *md = mq->data;
- int stat = BLKPREP_OK;
-
- /*
- * If we have no device, we haven't finished initialising.
- */
- if (!md || !mq->card) {
- printk(KERN_ERR "%s: killing request - no device/host\n",
- req->rq_disk->disk_name);
- stat = BLKPREP_KILL;
- }
-
- return stat;
-}
-
static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
{
int err;
@@ -462,11 +443,10 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
if (ret)
goto err_putdisk;
- md->queue.prep_fn = mmc_blk_prep_rq;
md->queue.issue_fn = mmc_blk_issue_rq;
md->queue.data = md;
- md->disk->major = major;
+ md->disk->major = MMC_BLOCK_MAJOR;
md->disk->first_minor = devidx << MMC_SHIFT;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
@@ -634,14 +614,9 @@ static int __init mmc_blk_init(void)
{
int res = -ENOMEM;
- res = register_blkdev(major, "mmc");
- if (res < 0) {
- printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
- major, res);
+ res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
+ if (res)
goto out;
- }
- if (major == 0)
- major = res;
return mmc_register_driver(&mmc_driver);
@@ -652,7 +627,7 @@ static int __init mmc_blk_init(void)
static void __exit mmc_blk_exit(void)
{
mmc_unregister_driver(&mmc_driver);
- unregister_blkdev(major, "mmc");
+ unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
}
module_init(mmc_blk_init);
@@ -661,5 +636,3 @@ module_exit(mmc_blk_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-module_param(major, int, 0444);
-MODULE_PARM_DESC(major, "specify the major device number for MMC block driver");
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 2e77963db334..dd97bc798409 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -20,40 +20,21 @@
#define MMC_QUEUE_SUSPENDED (1 << 0)
/*
- * Prepare a MMC request. Essentially, this means passing the
- * preparation off to the media driver. The media driver will
- * create a mmc_io_request in req->special.
+ * Prepare a MMC request. This just filters out odd stuff.
*/
static int mmc_prep_request(struct request_queue *q, struct request *req)
{
- struct mmc_queue *mq = q->queuedata;
- int ret = BLKPREP_KILL;
-
- if (blk_special_request(req)) {
- /*
- * Special commands already have the command
- * blocks already setup in req->special.
- */
- BUG_ON(!req->special);
-
- ret = BLKPREP_OK;
- } else if (blk_fs_request(req) || blk_pc_request(req)) {
- /*
- * Block I/O requests need translating according
- * to the protocol.
- */
- ret = mq->prep_fn(mq, req);
- } else {
- /*
- * Everything else is invalid.
- */
+ /*
+ * We only like normal block requests.
+ */
+ if (!blk_fs_request(req) && !blk_pc_request(req)) {
blk_dump_rq_flags(req, "MMC bad request");
+ return BLKPREP_KILL;
}
- if (ret == BLKPREP_OK)
- req->cmd_flags |= REQ_DONTPREP;
+ req->cmd_flags |= REQ_DONTPREP;
- return ret;
+ return BLKPREP_OK;
}
static int mmc_queue_thread(void *d)
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index c9f139e764f6..1590b3f3f1f7 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -10,20 +10,12 @@ struct mmc_queue {
struct semaphore thread_sem;
unsigned int flags;
struct request *req;
- int (*prep_fn)(struct mmc_queue *, struct request *);
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
struct scatterlist *sg;
};
-struct mmc_io_request {
- struct request *rq;
- int num;
- struct mmc_command selcmd; /* mmc_queue private */
- struct mmc_command cmd[4]; /* max 4 commands */
-};
-
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
extern void mmc_cleanup_queue(struct mmc_queue *);
extern void mmc_queue_suspend(struct mmc_queue *);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index c1dfd03d559a..918477c490b0 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -15,6 +15,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
#include "core.h"
#include "sysfs.h"
@@ -192,6 +193,16 @@ static int mmc_read_switch(struct mmc_card *card)
int err;
u8 *status;
+ if (card->scr.sda_vsn < SCR_SPEC_VER_1)
+ return MMC_ERR_NONE;
+
+ if (!(card->csd.cmdclass & CCC_SWITCH)) {
+ printk(KERN_WARNING "%s: card lacks mandatory switch "
+ "function, performance might suffer.\n",
+ mmc_hostname(card->host));
+ return MMC_ERR_NONE;
+ }
+
err = MMC_ERR_FAILED;
status = kmalloc(64, GFP_KERNEL);
@@ -204,10 +215,9 @@ static int mmc_read_switch(struct mmc_card *card)
err = mmc_sd_switch(card, 0, 0, 1, status);
if (err != MMC_ERR_NONE) {
- /*
- * Card not supporting high-speed will ignore the
- * command.
- */
+ printk(KERN_WARNING "%s: problem reading switch "
+ "capabilities, performance might suffer.\n",
+ mmc_hostname(card->host));
err = MMC_ERR_NONE;
goto out;
}
@@ -229,6 +239,12 @@ static int mmc_switch_hs(struct mmc_card *card)
int err;
u8 *status;
+ if (card->scr.sda_vsn < SCR_SPEC_VER_1)
+ return MMC_ERR_NONE;
+
+ if (!(card->csd.cmdclass & CCC_SWITCH))
+ return MMC_ERR_NONE;
+
if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
return MMC_ERR_NONE;
@@ -402,7 +418,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
/*
* Switch to wider bus (if supported).
*/
- if ((host->caps && MMC_CAP_4_BIT_DATA) &&
+ if ((host->caps & MMC_CAP_4_BIT_DATA) &&
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
if (err != MMC_ERR_NONE)
@@ -411,6 +427,21 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
}
+ /*
+ * Check if read-only switch is active.
+ */
+ if (!oldcard) {
+ 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);
+ }
+ }
+
if (!oldcard)
host->card = card;
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index e37943c314cb..5b00c194b628 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -417,7 +417,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
blocks = 0;
}
- if (cmd->opcode == MMC_STOP_TRANSMISSION)
+ if (host->flags & FL_SENT_STOP)
cmdr |= AT91_MCI_TRCMD_STOP;
if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
@@ -563,8 +563,7 @@ static void at91mci_completed_command(struct at91mci_host *host)
if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
- if ((status & AT91_MCI_RCRCE) &&
- ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
+ if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
cmd->error = MMC_ERR_NONE;
}
else {
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index b7156a4555b5..52b63f11ddd6 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -76,8 +76,7 @@ const struct {
#endif
};
-#define AU1XMMC_CONTROLLER_COUNT \
- (sizeof(au1xmmc_card_table) / sizeof(au1xmmc_card_table[0]))
+#define AU1XMMC_CONTROLLER_COUNT (ARRAY_SIZE(au1xmmc_card_table))
/* This array stores pointers for the hosts (used by the IRQ handler) */
struct au1xmmc_host *au1xmmc_hosts[AU1XMMC_CONTROLLER_COUNT];
@@ -187,9 +186,8 @@ static void au1xmmc_tasklet_finish(unsigned long param)
}
static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
- struct mmc_command *cmd)
+ struct mmc_command *cmd, unsigned int flags)
{
-
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) {
@@ -213,24 +211,16 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
return MMC_ERR_INVALID;
}
- switch(cmd->opcode) {
- case MMC_READ_SINGLE_BLOCK:
- case SD_APP_SEND_SCR:
- mmccmd |= SD_CMD_CT_2;
- break;
- case MMC_READ_MULTIPLE_BLOCK:
- mmccmd |= SD_CMD_CT_4;
- break;
- case MMC_WRITE_BLOCK:
- mmccmd |= SD_CMD_CT_1;
- break;
-
- case MMC_WRITE_MULTIPLE_BLOCK:
- mmccmd |= SD_CMD_CT_3;
- break;
- case MMC_STOP_TRANSMISSION:
- mmccmd |= SD_CMD_CT_7;
- break;
+ if (flags & MMC_DATA_READ) {
+ if (flags & MMC_DATA_MULTI)
+ mmccmd |= SD_CMD_CT_4;
+ else
+ mmccmd |= SD_CMD_CT_2;
+ } else if (flags & MMC_DATA_WRITE) {
+ if (flags & MMC_DATA_MULTI)
+ mmccmd |= SD_CMD_CT_3;
+ else
+ mmccmd |= SD_CMD_CT_1;
}
au_writel(cmd->arg, HOST_CMDARG(host));
@@ -665,6 +655,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
{
struct au1xmmc_host *host = mmc_priv(mmc);
+ unsigned int flags = 0;
int ret = MMC_ERR_NONE;
WARN_ON(irqs_disabled());
@@ -677,11 +668,12 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
if (mrq->data) {
FLUSH_FIFO(host);
+ flags = mrq->data->flags;
ret = au1xmmc_prepare_data(host, mrq->data);
}
if (ret == MMC_ERR_NONE)
- ret = au1xmmc_send_command(host, 0, mrq->cmd);
+ ret = au1xmmc_send_command(host, 0, mrq->cmd, flags);
if (ret != MMC_ERR_NONE) {
mrq->cmd->error = ret;
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 1914e65d4db1..b0824a38f425 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -522,28 +522,10 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
}
if (status & OMAP_MMC_STAT_CARD_ERR) {
- if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) {
- u32 response = OMAP_MMC_READ(host, RSP6)
- | (OMAP_MMC_READ(host, RSP7) << 16);
- /* STOP sometimes sets must-ignore bits */
- if (!(response & (R1_CC_ERROR
- | R1_ILLEGAL_COMMAND
- | R1_COM_CRC_ERROR))) {
- end_command = 1;
- continue;
- }
- }
-
- dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n",
+ dev_dbg(mmc_dev(host->mmc),
+ "ignoring card status error (CMD%d)\n",
host->cmd->opcode);
- if (host->cmd) {
- host->cmd->error = MMC_ERR_FAILED;
- end_command = 1;
- }
- if (host->data) {
- host->data->error = MMC_ERR_FAILED;
- transfer_error = 1;
- }
+ end_command = 1;
}
/*
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index d97d3864b57f..f8985c508bb9 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -232,20 +232,14 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
/*
* workaround for erratum #42:
* Intel PXA27x Family Processor Specification Update Rev 001
+ * A bogus CRC error can appear if the msb of a 136 bit
+ * response is a one.
*/
- if (cmd->opcode == MMC_ALL_SEND_CID ||
- cmd->opcode == MMC_SEND_CSD ||
- cmd->opcode == MMC_SEND_CID) {
- /* a bogus CRC error can appear if the msb of
- the 15 byte response is a one */
- if ((cmd->resp[0] & 0x80000000) == 0)
- cmd->error = MMC_ERR_BADCRC;
- } else {
- pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode);
- }
-#else
- cmd->error = MMC_ERR_BADCRC;
+ if (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000) {
+ pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
+ } else
#endif
+ cmd->error = MMC_ERR_BADCRC;
}
pxamci_disable_irq(host, END_CMD_RES);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ff5bf73cdd25..a359efdd77eb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -963,6 +963,15 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
sdhci_transfer_pio(host);
+ /*
+ * We currently don't do anything fancy with DMA
+ * boundaries, but as we can't disable the feature
+ * we need to at least restart the transfer.
+ */
+ if (intmask & SDHCI_INT_DMA_END)
+ writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
+ host->ioaddr + SDHCI_DMA_ADDRESS);
+
if (intmask & SDHCI_INT_DATA_END)
sdhci_finish_data(host);
}