Explorar el Código

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
Linus Torvalds hace 17 años
padre
commit
1ff6f3dbfb
Se han modificado 4 ficheros con 36 adiciones y 26 borrados
  1. 1 3
      drivers/mmc/core/bus.c
  2. 1 3
      drivers/mmc/core/host.c
  3. 33 20
      drivers/mmc/host/sdhci.c
  4. 1 0
      drivers/mmc/host/sdhci.h

+ 1 - 3
drivers/mmc/core/bus.c

@@ -186,12 +186,10 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host)
 {
 {
 	struct mmc_card *card;
 	struct mmc_card *card;
 
 
-	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+	card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
 	if (!card)
 	if (!card)
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 
 
-	memset(card, 0, sizeof(struct mmc_card));
-
 	card->host = host;
 	card->host = host;
 
 
 	device_initialize(&card->dev);
 	device_initialize(&card->dev);

+ 1 - 3
drivers/mmc/core/host.c

@@ -58,12 +58,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 {
 {
 	struct mmc_host *host;
 	struct mmc_host *host;
 
 
-	host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+	host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
 	if (!host)
 	if (!host)
 		return NULL;
 		return NULL;
 
 
-	memset(host, 0, sizeof(struct mmc_host) + extra);
-
 	host->parent = dev;
 	host->parent = dev;
 	host->class_dev.parent = dev;
 	host->class_dev.parent = dev;
 	host->class_dev.class = &mmc_host_class;
 	host->class_dev.class = &mmc_host_class;

+ 33 - 20
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->blksz > host->mmc->max_blk_size);
 	BUG_ON(data->blocks > 65535);
 	BUG_ON(data->blocks > 65535);
 
 
+	host->data = data;
+	host->data_early = 0;
+
 	/* timeout in us */
 	/* timeout in us */
 	target_timeout = data->timeout_ns / 1000 +
 	target_timeout = data->timeout_ns / 1000 +
 		data->timeout_clks / host->clock;
 		data->timeout_clks / host->clock;
@@ -443,11 +446,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 {
 {
 	u16 mode;
 	u16 mode;
 
 
-	WARN_ON(host->data);
-
 	if (data == NULL)
 	if (data == NULL)
 		return;
 		return;
 
 
+	WARN_ON(!host->data);
+
 	mode = SDHCI_TRNS_BLK_CNT_EN;
 	mode = SDHCI_TRNS_BLK_CNT_EN;
 	if (data->blocks > 1)
 	if (data->blocks > 1)
 		mode |= SDHCI_TRNS_MULTI;
 		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.
 	 * 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
 	else
 		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
 		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
 	data->bytes_xfered = data->blksz * (data->blocks - blocks);
 	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;
 	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);
 		tasklet_schedule(&host->finish_tasklet);
 
 
 	host->cmd = NULL;
 	host->cmd = NULL;
@@ -929,9 +933,9 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 	BUG_ON(intmask == 0);
 	BUG_ON(intmask == 0);
 
 
 	if (!host->cmd) {
 	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);
 		sdhci_dumpregs(host);
 		return;
 		return;
 	}
 	}
@@ -961,9 +965,9 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 		if (intmask & SDHCI_INT_DATA_END)
 		if (intmask & SDHCI_INT_DATA_END)
 			return;
 			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);
 		sdhci_dumpregs(host);
 
 
 		return;
 		return;
@@ -991,8 +995,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 			writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
 			writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
 				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;
 	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
 	if (mmc->max_blk_size >= 3) {
 	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);
 			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.
 	 * Maximum block count.

+ 1 - 0
drivers/mmc/host/sdhci.h

@@ -182,6 +182,7 @@ struct sdhci_host {
 	struct mmc_request	*mrq;		/* Current request */
 	struct mmc_request	*mrq;		/* Current request */
 	struct mmc_command	*cmd;		/* Current command */
 	struct mmc_command	*cmd;		/* Current command */
 	struct mmc_data		*data;		/* Current data request */
 	struct mmc_data		*data;		/* Current data request */
+	int			data_early:1;	/* Data finished before cmd */
 
 
 	struct scatterlist	*cur_sg;	/* We're working on this */
 	struct scatterlist	*cur_sg;	/* We're working on this */
 	int			num_sg;		/* Entries left */
 	int			num_sg;		/* Entries left */