linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Philip Langdale <philipl@overt.org>
To: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Tobias Bengtsson <tobbe@tobbe.nu>,
	sdhci-devel@list.drzeus.cx, LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] sdhci: Add quirk to support polling for card presence
Date: Mon, 14 May 2007 20:21:52 -0700	[thread overview]
Message-ID: <46492750.40408@overt.org> (raw)
In-Reply-To: <46483A25.8030301@drzeus.cx>

There is apparently at least one instance of the Ricoh SDHCI
implementation out there where card insertion and removal
interrupts do not work - so the only way to detect a change
in the presence of a card is to poll.

This changes adds a polling quirk for the particular model
reported. Others may be affected, but we can add them as they
arise.

As part of this change, caching of the present state is introduced
to reduce the amount of work done when nothing has changed. This
cached state is referred to in the standard interrupt path but as
it is interrupt driven - the cached and new state should never be
the same so it will cause no change in behaviour.

Signed-off-by: Philip Langdale <philipl@overt.org>

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ff5bf73..2d5ec61 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -34,6 +34,7 @@ static unsigned int debug_quirks = 0;
 /* Controller doesn't like some resets when there is no card inserted. */
 #define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
 #define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
+#define SDHCI_QUIRK_NO_CARD_DETECT_INT			(1<<4)

 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -48,6 +49,16 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
 		.vendor		= PCI_VENDOR_ID_RICOH,
 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
+		.subvendor	= PCI_SUBVENDOR_ID_FUJITSU_SIEMENS,
+		.subdevice	= PCI_SUBDEVICE_ID_FUJITSU_SIEMENS_SI1520,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
+				  SDHCI_QUIRK_NO_CARD_NO_RESET |
+				  SDHCI_QUIRK_NO_CARD_DETECT_INT,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C822,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
 		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
@@ -788,13 +799,18 @@ static void sdhci_tasklet_card(unsigned long param)
 {
 	struct sdhci_host *host;
 	unsigned long flags;
+	int present;
+	int polling;

 	host = (struct sdhci_host*)param;

+	polling = host->chip->quirks & SDHCI_QUIRK_NO_CARD_DETECT_INT;
+
 	spin_lock_irqsave(&host->lock, flags);

-	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
-		if (host->mrq) {
+	present = readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT;
+	if (present != host->present) {
+		if (!present && host->mrq) {
 			printk(KERN_ERR "%s: Card removed during transfer!\n",
 				mmc_hostname(host->mmc));
 			printk(KERN_ERR "%s: Resetting controller.\n",
@@ -806,11 +822,21 @@ static void sdhci_tasklet_card(unsigned long param)
 			host->mrq->cmd->error = MMC_ERR_FAILED;
 			tasklet_schedule(&host->finish_tasklet);
 		}
-	}

-	spin_unlock_irqrestore(&host->lock, flags);
+		host->present = present;
+
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		mmc_detect_change(host->mmc,
+				  polling ? 0 : msecs_to_jiffies(500));
+	} else {
+		spin_unlock_irqrestore(&host->lock, flags);
+	}

-	mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+	if (polling) {
+		host->detect_timer.expires = jiffies + HZ;
+		add_timer(&host->detect_timer);
+	}
 }

 static void sdhci_tasklet_finish(unsigned long param)
@@ -865,6 +891,15 @@ static void sdhci_tasklet_finish(unsigned long param)
 	mmc_request_done(host->mmc, mrq);
 }

+static void sdhci_detect_timer(unsigned long data)
+{
+	struct sdhci_host *host;
+
+	host = (struct sdhci_host*)data;
+
+	tasklet_schedule(&host->card_tasklet);
+}
+
 static void sdhci_timeout_timer(unsigned long data)
 {
 	struct sdhci_host *host;
@@ -1329,6 +1364,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 	 */
 	mmc->max_blk_count = 65535;

+	host->present = readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT;;
+
 	/*
 	 * Init tasklets.
 	 */
@@ -1344,6 +1381,12 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 	if (ret)
 		goto untasklet;

+	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_DETECT_INT) {
+		setup_timer(&host->detect_timer, sdhci_detect_timer, (unsigned long)host);
+		host->detect_timer.expires = jiffies + HZ;
+		add_timer(&host->detect_timer);
+	}
+
 	sdhci_init(host);

 #ifdef CONFIG_MMC_DEBUG
@@ -1396,6 +1439,10 @@ static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
 	tasklet_kill(&host->card_tasklet);
 	tasklet_kill(&host->finish_tasklet);

+	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_DETECT_INT) {
+		del_timer_sync(&host->detect_timer);
+	}
+
 	iounmap(host->ioaddr);

 	pci_release_region(pdev, host->bar);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7400f4b..fafd1c4 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -198,6 +198,9 @@ struct sdhci_host {
 	struct tasklet_struct	finish_tasklet;

 	struct timer_list	timer;		/* Timer for timeouts */
+
+	struct timer_list	detect_timer;	/* Timer for card polling */
+	int			present;	/* Cached card present state */
 };

 struct sdhci_chip {
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ae849f0..e10eeaf 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2049,6 +2049,9 @@
 #define PCI_VENDOR_ID_VITESSE		0x1725
 #define PCI_DEVICE_ID_VITESSE_VSC7174	0x7174

+#define PCI_SUBVENDOR_ID_FUJITSU_SIEMENS	0x1734
+#define PCI_SUBDEVICE_ID_FUJITSU_SIEMENS_SI1520	0x10ad
+
 #define PCI_VENDOR_ID_LINKSYS		0x1737
 #define PCI_DEVICE_ID_LINKSYS_EG1064	0x1064



  reply	other threads:[~2007-05-15  3:22 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-13 23:20 [PATCH] sdhci: Add quirk to support polling for card presence Philip Langdale
2007-05-14 10:29 ` Pierre Ossman
2007-05-15  3:21   ` Philip Langdale [this message]
2007-05-17 23:01 ` Pierre Ossman
2007-05-18 10:58   ` Tobias Bengtsson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=46492750.40408@overt.org \
    --to=philipl@overt.org \
    --cc=drzeus-list@drzeus.cx \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sdhci-devel@list.drzeus.cx \
    --cc=tobbe@tobbe.nu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).