summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-23 21:36:13 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-23 21:36:13 -0700
commit1ff6f3dbfb366b464869d3558406e498cb3e1159 (patch)
tree3265b96ac28c297adc6f24b1fb22454aa9b7b1ac
parent2b56fec64faae9fc5c3e61bbfb851b7985292cd5 (diff)
parentb67ac3f339c76dfea3cc75fc0285b6d13edc35fa (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: sdhci: tell which spurious interrupt we got sdhci: handle data interrupts during command mmc: ignore bad max block size in sdhci sdhci: be more cautious about block count register drivers/mmc/core/host.c: kmalloc + memset conversion to kzalloc drivers/mmc/core/bus.c: kmalloc + memset conversion to kzalloc
-rw-r--r--drivers/mmc/core/bus.c4
-rw-r--r--drivers/mmc/core/host.c4
-rw-r--r--drivers/mmc/host/sdhci.c53
-rw-r--r--drivers/mmc/host/sdhci.h1
4 files changed, 36 insertions, 26 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index fe0e785ed7d2..817a79462b3d 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -186,12 +186,10 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host)
{
struct mmc_card *card;
- card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+ card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
if (!card)
return ERR_PTR(-ENOMEM);
- memset(card, 0, sizeof(struct mmc_card));
-
card->host = host;
device_initialize(&card->dev);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6a7e29849603..2c7ce8f43a9a 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -58,12 +58,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
struct mmc_host *host;
- host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+ host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host)
return NULL;
- memset(host, 0, sizeof(struct mmc_host) + extra);
-
host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f2bc87ac24f7..20a7d89e01ba 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -385,6 +385,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
+ host->data = data;
+ host->data_early = 0;
+
/* timeout in us */
target_timeout = data->timeout_ns / 1000 +
data->timeout_clks / host->clock;
@@ -443,11 +446,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
{
u16 mode;
- WARN_ON(host->data);
-
if (data == NULL)
return;
+ WARN_ON(!host->data);
+
mode = SDHCI_TRNS_BLK_CNT_EN;
if (data->blocks > 1)
mode |= SDHCI_TRNS_MULTI;
@@ -477,8 +480,8 @@ static void sdhci_finish_data(struct sdhci_host *host)
/*
* Controller doesn't count down when in single block mode.
*/
- if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
- blocks = 0;
+ if (data->blocks == 1)
+ blocks = (data->error == MMC_ERR_NONE) ? 0 : 1;
else
blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
data->bytes_xfered = data->blksz * (data->blocks - blocks);
@@ -600,9 +603,10 @@ static void sdhci_finish_command(struct sdhci_host *host)
host->cmd->error = MMC_ERR_NONE;
- if (host->cmd->data)
- host->data = host->cmd->data;
- else
+ if (host->data && host->data_early)
+ sdhci_finish_data(host);
+
+ if (!host->cmd->data)
tasklet_schedule(&host->finish_tasklet);
host->cmd = NULL;
@@ -929,9 +933,9 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
BUG_ON(intmask == 0);
if (!host->cmd) {
- printk(KERN_ERR "%s: Got command interrupt even though no "
- "command operation was in progress.\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
+ "though no command operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_dumpregs(host);
return;
}
@@ -961,9 +965,9 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (intmask & SDHCI_INT_DATA_END)
return;
- printk(KERN_ERR "%s: Got data interrupt even though no "
- "data operation was in progress.\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
+ "though no data operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_dumpregs(host);
return;
@@ -991,8 +995,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
host->ioaddr + SDHCI_DMA_ADDRESS);
- if (intmask & SDHCI_INT_DATA_END)
- sdhci_finish_data(host);
+ if (intmask & SDHCI_INT_DATA_END) {
+ if (host->cmd) {
+ /*
+ * Data managed to finish before the
+ * command completed. Make sure we do
+ * things in the proper order.
+ */
+ host->data_early = 1;
+ } else {
+ sdhci_finish_data(host);
+ }
+ }
}
}
@@ -1347,12 +1361,11 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
*/
mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
if (mmc->max_blk_size >= 3) {
- printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
host->slot_descr);
- ret = -ENODEV;
- goto unmap;
- }
- mmc->max_blk_size = 512 << mmc->max_blk_size;
+ mmc->max_blk_size = 512;
+ } else
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
/*
* Maximum block count.
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d157776c1149..e28987d6d2eb 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -182,6 +182,7 @@ struct sdhci_host {
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
struct mmc_data *data; /* Current data request */
+ int data_early:1; /* Data finished before cmd */
struct scatterlist *cur_sg; /* We're working on this */
int num_sg; /* Entries left */