aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/at91_mci.c4
-rw-r--r--drivers/mmc/au1xmmc.c2
-rw-r--r--drivers/mmc/imxmmc.c4
-rw-r--r--drivers/mmc/mmc_block.c104
-rw-r--r--drivers/mmc/mmci.c4
-rw-r--r--drivers/mmc/omap.c4
-rw-r--r--drivers/mmc/pxamci.c6
-rw-r--r--drivers/mmc/sdhci.c4
-rw-r--r--drivers/mmc/tifm_sd.c14
-rw-r--r--drivers/mmc/wbsd.c2
10 files changed, 117 insertions, 31 deletions
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index cb142a6..494b23f 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -661,7 +661,7 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/*
* Handle an interrupt
*/
-static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t at91_mci_irq(int irq, void *devid)
{
struct at91mci_host *host = devid;
int completed = 0;
@@ -754,7 +754,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs)
+static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
{
struct at91mci_host *host = _host;
int present = !at91_get_gpio_value(irq);
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 61268da..53ffcbb 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -750,7 +750,7 @@ static void au1xmmc_dma_callback(int irq, void *dev_id)
#define STATUS_DATA_IN (SD_STATUS_NE)
#define STATUS_DATA_OUT (SD_STATUS_TH)
-static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
{
u32 status;
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index 1b79dd2..659d4a8 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -635,7 +635,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
return trans_done;
}
-static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+static void imxmci_dma_irq(int dma, void *devid)
{
struct imxmci_host *host = devid;
uint32_t stat = MMC_STATUS;
@@ -646,7 +646,7 @@ static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
tasklet_schedule(&host->tasklet);
}
-static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t imxmci_irq(int irq, void *devid)
{
struct imxmci_host *host = devid;
uint32_t stat = MMC_STATUS;
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index c1293f1..f9027c8 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -28,6 +28,7 @@
#include <linux/kdev_t.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -154,6 +155,71 @@ static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
return stat;
}
+static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+{
+ int err;
+ u32 blocks;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ unsigned int timeout_us;
+
+ struct scatterlist sg;
+
+ 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;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
+ return (u32)-1;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 100;
+ data.timeout_clks = card->csd.tacc_clks * 100;
+
+ timeout_us = data.timeout_ns / 1000;
+ timeout_us += data.timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (timeout_us > 100000) {
+ data.timeout_ns = 100000000;
+ data.timeout_clks = 0;
+ }
+
+ data.blksz = 4;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, &blocks, 4);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
+ return (u32)-1;
+
+ blocks = ntohl(blocks);
+
+ return blocks;
+}
+
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
@@ -184,10 +250,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
/*
* If the host doesn't support multiple block writes, force
- * block writes to single block.
+ * block writes to single block. SD cards are excepted from
+ * this rule as they support querying the number of
+ * successfully written sectors.
*/
if (rq_data_dir(req) != READ &&
- !(card->host->caps & MMC_CAP_MULTIWRITE))
+ !(card->host->caps & MMC_CAP_MULTIWRITE) &&
+ !mmc_card_sd(card))
brq.data.blocks = 1;
if (brq.data.blocks > 1) {
@@ -276,24 +345,41 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
return 1;
cmd_err:
- mmc_card_release_host(card);
-
ret = 1;
- /*
- * For writes and where the host claims to support proper
- * error reporting, we first ok the successful blocks.
+ /*
+ * If this is an SD card and we're writing, we can first
+ * mark the known good sectors as ok.
+ *
+ * If the card is not SD, we can still ok written sectors
+ * if the controller can do proper error reporting.
*
* For reads we just fail the entire chunk as that should
* be safe in all cases.
*/
- if (rq_data_dir(req) != READ &&
- (card->host->caps & MMC_CAP_MULTIWRITE)) {
+ if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
+ u32 blocks;
+ unsigned int bytes;
+
+ blocks = mmc_sd_num_wr_blocks(card);
+ if (blocks != (u32)-1) {
+ if (card->csd.write_partial)
+ bytes = blocks << md->block_bits;
+ else
+ bytes = blocks << 9;
+ spin_lock_irq(&md->lock);
+ ret = end_that_request_chunk(req, 1, bytes);
+ spin_unlock_irq(&md->lock);
+ }
+ } else if (rq_data_dir(req) != READ &&
+ (card->host->caps & MMC_CAP_MULTIWRITE)) {
spin_lock_irq(&md->lock);
ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
spin_unlock_irq(&md->lock);
}
+ mmc_card_release_host(card);
+
spin_lock_irq(&md->lock);
while (ret) {
ret = end_that_request_chunk(req, 0,
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 2b5a0cc..828503c 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -261,7 +261,7 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
/*
* PIO data transfer IRQ handler.
*/
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
void __iomem *base = host->base;
@@ -347,7 +347,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
/*
* Handle completion of command and data transfers.
*/
-static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmci_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
u32 status;
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index 52c9e52..762fa28 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -377,7 +377,7 @@ static inline void mmc_omap_report_irq(u16 status)
}
}
-static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
{
struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
u16 status;
@@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
{
struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index ef35090..a526698 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -299,7 +299,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
return 1;
}
-static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t pxamci_irq(int irq, void *devid)
{
struct pxamci_host *host = devid;
unsigned int ireg;
@@ -399,13 +399,13 @@ static struct mmc_host_ops pxamci_ops = {
.set_ios = pxamci_set_ios,
};
-static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+static void pxamci_dma_irq(int dma, void *devid)
{
printk(KERN_ERR "DMA%d: IRQ???\n", dma);
DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
}
-static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{
struct pxamci_host *host = mmc_priv(devid);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 20711ac..9a7d39b 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -985,7 +985,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}
-static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
{
irqreturn_t result;
struct sdhci_host* host = dev_id;
@@ -1329,7 +1329,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
tasklet_init(&host->finish_tasklet,
sdhci_tasklet_finish, (unsigned long)host);
- setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
+ setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
host->slot_descr, host);
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index 6d23dc0..2bacff6 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -501,13 +501,13 @@ static void tifm_sd_end_cmd(void *data)
struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
- struct mmc_data *r_data = 0;
+ struct mmc_data *r_data = NULL;
unsigned long flags;
spin_lock_irqsave(&sock->lock, flags);
mrq = host->req;
- host->req = 0;
+ host->req = NULL;
host->state = IDLE;
if (!mrq) {
@@ -546,7 +546,7 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
struct tifm_dev *sock = host->dev;
unsigned long flags;
struct mmc_data *r_data = mrq->cmd->data;
- char *t_buffer = 0;
+ char *t_buffer = NULL;
if (r_data) {
t_buffer = kmap(r_data->sg->page);
@@ -613,13 +613,13 @@ static void tifm_sd_end_cmd_nodma(void *data)
struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
- struct mmc_data *r_data = 0;
+ struct mmc_data *r_data = NULL;
unsigned long flags;
spin_lock_irqsave(&sock->lock, flags);
mrq = host->req;
- host->req = 0;
+ host->req = NULL;
host->state = IDLE;
if (!mrq) {
@@ -644,7 +644,7 @@ static void tifm_sd_end_cmd_nodma(void *data)
r_data->bytes_xfered += r_data->blksz -
readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
}
- host->buffer = 0;
+ host->buffer = NULL;
host->buffer_pos = 0;
host->buffer_size = 0;
}
@@ -895,7 +895,7 @@ static void tifm_sd_remove(struct tifm_dev *sock)
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
- tifm_set_drvdata(sock, 0);
+ tifm_set_drvdata(sock, NULL);
mmc_free_host(mmc);
}
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 88c6f0b..ced309b 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1256,7 +1256,7 @@ end:
* Interrupt handling
*/
-static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wbsd_irq(int irq, void *dev_id)
{
struct wbsd_host *host = dev_id;
int isr;