瀏覽代碼

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:
  mmc: remove unused 'mode' from the mmc_host structure
  sdhci: support JMicron JMB38x chips
  sdhci: use PIO when DMA can't satisfy the request
  sdhci: don't warn about sdhci 2.0 controllers
  sdhci: describe quirks
Linus Torvalds 17 年之前
父節點
當前提交
d55653377d
共有 4 個文件被更改,包括 61 次插入10 次删除
  1. 58 5
      drivers/mmc/host/sdhci.c
  2. 2 1
      drivers/mmc/host/sdhci.h
  3. 0 4
      include/linux/mmc/host.h
  4. 1 0
      include/linux/pci_ids.h

+ 58 - 5
drivers/mmc/host/sdhci.c

@@ -7,6 +7,10 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
+ *
+ * Thanks to the following companies for their support:
+ *
+ *     - JMicron (hardware and technical support)
  */
 
 #include <linux/delay.h>
@@ -26,13 +30,29 @@
 
 static unsigned int debug_quirks = 0;
 
+/*
+ * Different quirks to handle when the hardware deviates from a strict
+ * interpretation of the SDHCI specification.
+ */
+
+/* Controller doesn't honor resets unless we touch the clock register */
 #define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
+/* Controller has bad caps bits, but really supports DMA */
 #define SDHCI_QUIRK_FORCE_DMA				(1<<1)
 /* Controller doesn't like some resets when there is no card inserted. */
 #define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
+/* Controller doesn't like clearing the power reg before a change */
 #define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
+/* Controller has flaky internal state so reset it on each ios change */
 #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
+/* Controller has an unusable DMA engine */
 #define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
+/* Controller can only DMA from 32-bit aligned addresses */
+#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<6)
+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
+/* Controller needs to be reset after each request to stay stable */
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -97,6 +117,16 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
 	},
 
+	{
+		.vendor         = PCI_VENDOR_ID_JMICRON,
+		.device         = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.driver_data    = SDHCI_QUIRK_32BIT_DMA_ADDR |
+				  SDHCI_QUIRK_32BIT_DMA_SIZE |
+				  SDHCI_QUIRK_RESET_AFTER_REQUEST,
+	},
+
 	{	/* Generic SD host controller */
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 	},
@@ -419,7 +449,29 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
 	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
 
-	if (host->flags & SDHCI_USE_DMA) {
+	if (host->flags & SDHCI_USE_DMA)
+		host->flags |= SDHCI_REQ_USE_DMA;
+
+	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
+		(host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
+		((data->blksz * data->blocks) & 0x3))) {
+		DBG("Reverting to PIO because of transfer size (%d)\n",
+			data->blksz * data->blocks);
+		host->flags &= ~SDHCI_REQ_USE_DMA;
+	}
+
+	/*
+	 * The assumption here being that alignment is the same after
+	 * translation to device address space.
+	 */
+	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
+		(host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+		(data->sg->offset & 0x3))) {
+		DBG("Reverting to PIO because of bad alignment\n");
+		host->flags &= ~SDHCI_REQ_USE_DMA;
+	}
+
+	if (host->flags & SDHCI_REQ_USE_DMA) {
 		int count;
 
 		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
@@ -456,7 +508,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 		mode |= SDHCI_TRNS_MULTI;
 	if (data->flags & MMC_DATA_READ)
 		mode |= SDHCI_TRNS_READ;
-	if (host->flags & SDHCI_USE_DMA)
+	if (host->flags & SDHCI_REQ_USE_DMA)
 		mode |= SDHCI_TRNS_DMA;
 
 	writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
@@ -472,7 +524,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
 	data = host->data;
 	host->data = NULL;
 
-	if (host->flags & SDHCI_USE_DMA) {
+	if (host->flags & SDHCI_REQ_USE_DMA) {
 		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
 			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
 	}
@@ -886,7 +938,8 @@ static void sdhci_tasklet_finish(unsigned long param)
 	 */
 	if (mrq->cmd->error ||
 		(mrq->data && (mrq->data->error ||
-		(mrq->data->stop && mrq->data->stop->error)))) {
+		(mrq->data->stop && mrq->data->stop->error))) ||
+		(host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
 
 		/* Some controllers need this kick or reset won't work here */
 		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
@@ -1284,7 +1337,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
 	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
 	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
-	if (version != 0) {
+	if (version > 1) {
 		printk(KERN_ERR "%s: Unknown controller version (%d). "
 			"You may experience problems.\n", host->slot_descr,
 			version);

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

@@ -171,7 +171,8 @@ struct sdhci_host {
 	spinlock_t		lock;		/* Mutex */
 
 	int			flags;		/* Host attributes */
-#define SDHCI_USE_DMA		(1<<0)
+#define SDHCI_USE_DMA		(1<<0)		/* Host is DMA capable */
+#define SDHCI_REQ_USE_DMA	(1<<1)		/* Use DMA for this req. */
 
 	unsigned int		max_clk;	/* Max possible freq (MHz) */
 	unsigned int		timeout_clk;	/* Timeout freq (KHz) */

+ 0 - 4
include/linux/mmc/host.h

@@ -118,10 +118,6 @@ struct mmc_host {
 	unsigned int		removed:1;	/* host is being removed */
 #endif
 
-	unsigned int		mode;		/* current card mode of host */
-#define MMC_MODE_MMC		0
-#define MMC_MODE_SD		1
-
 	struct mmc_card		*card;		/* device attached to this host */
 
 	wait_queue_head_t	wq;

+ 1 - 0
include/linux/pci_ids.h

@@ -2148,6 +2148,7 @@
 #define PCI_DEVICE_ID_JMICRON_JMB365	0x2365
 #define PCI_DEVICE_ID_JMICRON_JMB366	0x2366
 #define PCI_DEVICE_ID_JMICRON_JMB368	0x2368
+#define PCI_DEVICE_ID_JMICRON_JMB38X_SD	0x2381
 
 #define PCI_VENDOR_ID_KORENIX		0x1982
 #define PCI_DEVICE_ID_KORENIX_JETCARDF0	0x1600