Zdenek Kabelac | 1 Sep 11:34 2009
Picon

Re: Regression in suspend to ram in 2.6.31-rc kernels

2009/8/31 Rafael J. Wysocki <rjw <at> sisk.pl>:
> On Monday 31 August 2009, Zdenek Kabelac wrote:
>> Hi
>>
>> I've noticed that my machine freezes while doing s2r and having
>> mounted filesystem from SD card.
>>
>> My system: Lenovo T61, 4GB, C2D, kernel 2.6.31-rc8
>>
>> Here is the trace of  suspend when SD card is inserted, follows resume
>> and again suspend and this time with mounted filesystem from SD card.
>>
>> System locks with: PM: Removing info for mmc:mmc0:b368
>> Also btusb_bulk_complete: errors are interesting - I've noticed few
>> bugzillas in the google.
>> I could try bisect to find the patch - but it will take time....
>> So hopefully this trace will help.
>
> Not really. :-(
>
> Is this a new regression in 2.6.31-rc, or does 2.6.30 also fail?
>

Well - all I know for now is this:  v2.6.30 goes to suspend (i.e.
machine turns to sleep), but resume fails - I do not get a single line
of output on serial console either - so it's hard to tell whether it
works or not - before suspend there are some INFO traces about lockdep
problems in cpu frequency.   v2.6.31-rc1 doesn't boot on my machine.
v2.6.31-rc2 seems to lock on suspend so this version is already
definitely broken. I may try to do some bisecting between these
(Continue reading)

Madhusudhan | 1 Sep 19:18 2009
Picon

mmcqd seem to use lot of cpu cycles

Hi,

While running one of the MMC use cases in the system I saw that mmcqd seems
to eat up a lot of cpu cycles. I saw a thread which discussed some details.

http://www.nabble.com/mmcqd-uses-a-large-amount-of-cpu-td23768078.html

Any clue on what this process is doing? If a low level driver is using DMA I
am not sure why there is so much load on the system due to mmcqd? Any
thoughts?

 
Regards,
Madhu

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo <at> vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

akpm | 1 Sep 23:45 2009

+ atmel-mci-unified-atmel-mci-drivers-avr32-at91.patch added to -mm tree


The patch titled
     atmel-mci: unified Atmel MCI drivers (AVR32 & AT91)
has been added to the -mm tree.  Its filename is
     atmel-mci-unified-atmel-mci-drivers-avr32-at91.patch

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/SubmitChecklist when testing your code ***

See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find
out what to do about this

The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/

------------------------------------------------------
Subject: atmel-mci: unified Atmel MCI drivers (AVR32 & AT91)
From: Rob Emanuele <rob <at> emanuele.us>

Unification of the atmel-mci driver to support the AT91 processors MCI
interface.  The atmel-mci driver currently supports the AVR32 and this
patch adds AT91 support.

Add read/write proof selection switch dependent on chip availability of
this feature.

(Continue reading)

akpm | 1 Sep 23:45 2009

+ at91-atmel-mci-platform-configuration-to-the-the-atmel-mci-driver.patch added to -mm tree


The patch titled
     AT91: atmel-mci: Platform configuration to the the atmel-mci driver
has been added to the -mm tree.  Its filename is
     at91-atmel-mci-platform-configuration-to-the-the-atmel-mci-driver.patch

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/SubmitChecklist when testing your code ***

See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find
out what to do about this

The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/

------------------------------------------------------
Subject: AT91: atmel-mci: Platform configuration to the the atmel-mci driver
From: Rob Emanuele <rob <at> emanuele.us>

Created a modified version of the at91sam9g20 evaluation kit platform
(board-sam9g20ek-2slot-mmc.c) and device support to make use of the
updated atmel-mci driver.

As the use of two slots modify GPIO pin allocation, we create another
board file.

(Continue reading)

Madhusudhan | 1 Sep 19:12 2009
Picon

mmcqd seem to use lot of cpu cycles

Hi,

 

While running one of the MMC use cases in the system I saw that mmcqd seems to eat up a lot of cpu cycles. I saw a thread which discussed some details.

 

http://www.nabble.com/mmcqd-uses-a-large-amount-of-cpu-td23768078.html

 

Any clue on what this process is doing? If a low level driver is using DMA I am not sure why there is so much load on the system due to mmcqd? Any thoughts?

 

Regards,

Madhu

 

 

 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel <at> lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Madhusudhan | 2 Sep 19:23 2009
Picon

mmcqd cpu utilization

Hi,

Has anyone monitored the cpu utilization percentage when a MMC/SD card is in
use? I have noticed that mmc_queue_thread "mmcqd" consumes a lot of cpu
cycles in a periodic fashion. What I mean here is that I see spikes of high
cpu utilization due to mmcqd. There will a cp or similar which will be
already consuming cpu to transfer data to the MMC/SD device. Further mmcqd
increases that load randomly to a high number.

Has anyone seen similar behavior? Any thoughts?

Regards,
Madhu  

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo <at> vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Pierre Ossman | 2 Sep 19:40 2009
Picon

Re: mmcqd cpu utilization

On Wed, 2 Sep 2009 12:23:59 -0500
"Madhusudhan" <madhu.cr <at> ti.com> wrote:

> Hi,
> 
> Has anyone monitored the cpu utilization percentage when a MMC/SD card is in
> use? I have noticed that mmc_queue_thread "mmcqd" consumes a lot of cpu
> cycles in a periodic fashion. What I mean here is that I see spikes of high
> cpu utilization due to mmcqd. There will a cp or similar which will be
> already consuming cpu to transfer data to the MMC/SD device. Further mmcqd
> increases that load randomly to a high number.
> 
> Has anyone seen similar behavior? Any thoughts?
> 

My guess would be that the omap driver doesn't (cannot?) use the
hardware to wait for busy to end, so the system must poll.

Anything better than that guess will require some profiling. :)

Rgds
--

-- 
     -- Pierre Ossman

  WARNING: This correspondence is being monitored by the
  Swedish government. Make sure your server uses encryption
  for SMTP traffic and consider using PGP for end-to-end
  encryption.
Nicolas Pitre | 2 Sep 20:37 2009

[PATCH 0/4] power management support for SDIO cards

This series is the core changes needed to support suspend/resume with
SDIO cards, and allow for special power management features needed to
implement things like the equivalent of wake-on-land for SDIO wireless
cards.  Further patches will eventually be posted for the SDHCI driver
and for the Libertas driver.

[PATCH 1/4] [MMC] core SDIO suspend/resume support
[PATCH 2/4] [MMC] propagate error codes back from bus drivers' suspend/resume methods
[PATCH 3/4] [MMC] make SDIO device/driver struct accessors public
[PATCH 4/4] [MMC] introduce API for special power management features

 drivers/mmc/core/core.c       |   45 +++++-
 drivers/mmc/core/core.h       |    4 +-
 drivers/mmc/core/mmc.c        |   15 +--
 drivers/mmc/core/sd.c         |   15 +--
 drivers/mmc/core/sdio.c       |  278 ++++++++++++++++++++++++-----------
 drivers/mmc/core/sdio_bus.c   |    3 -
 drivers/mmc/core/sdio_io.c    |   49 ++++++
 include/linux/mmc/host.h      |    5 +
 include/linux/mmc/pm.h        |   30 ++++
 include/linux/mmc/sdio_func.h |    8 +
 10 files changed, 329 insertions(+), 123 deletions(-)

Nicolas

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo <at> vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Nicolas Pitre | 2 Sep 20:37 2009

[PATCH 1/4] [MMC] core SDIO suspend/resume support

Currently, all SDIO cards are virtually removed upon a suspend, and
completely reprobed upon a resume.  This adds the suspend and resume
methods to the SDIO bus driver so to be able to dispatch those events
to the actual SDIO function drivers for real suspend/resume instead.

All active functions on a card must have a driver with both a suspend
and a resume method though.  Failing that, we fall back to the current
behavior of simply "removing" the card when suspending.

When resuming, we make sure the same card is still inserted by comparing
the vendor and product IDs.  If there is a mismatch, or if there is simply
no card anymore in the slot, then the previous card is "removed" and the
new card is detected.

Signed-off-by: Nicolas Pitre <nico <at> marvell.com>
---
 drivers/mmc/core/sdio.c |  285 ++++++++++++++++++++++++++++++++---------------
 1 files changed, 196 insertions(+), 89 deletions(-)

diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index fb99ccf..4c21b74 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
 <at>  <at>  -195,6 +195,134  <at>  <at>  static int sdio_enable_hs(struct mmc_card *card)
 }

 /*
+ * Handle the detection and initialisation of a card.
+ *
+ * In the case of a resume, "oldcard" will contain the card
+ * we're trying to reinitialise.
+ */
+static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
+			      struct mmc_card *oldcard)
+{
+	struct mmc_card *card;
+	int err;
+
+	BUG_ON(!host);
+	WARN_ON(!host->claimed);
+
+	/*
+	 * Inform the card of the voltage
+	 */
+	err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+	if (err)
+		goto err;
+
+	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	/*
+	 * Allocate card structure.
+	 */
+	card = mmc_alloc_card(host, NULL);
+	if (IS_ERR(card)) {
+		err = PTR_ERR(card);
+		goto err;
+	}
+
+	card->type = MMC_TYPE_SDIO;
+
+	/*
+	 * For native busses:  set card RCA and quit open drain mode.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_send_relative_addr(host, &card->rca);
+		if (err)
+			goto remove;
+
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
+
+	/*
+	 * Select card, as all following commands rely on that.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto remove;
+	}
+
+	/*
+	 * Read the common registers.
+	 */
+	err = sdio_read_cccr(card);
+	if (err)
+		goto remove;
+
+	/*
+	 * Read the common CIS tuples.
+	 */
+	err = sdio_read_common_cis(card);
+	if (err)
+		goto remove;
+
+	if (oldcard) {
+		int same = (card->cis.vendor == oldcard->cis.vendor &&
+			    card->cis.device == oldcard->cis.device);
+		mmc_remove_card(card);
+		if (!same) {
+			err = -ENOENT;
+			goto err;
+		}
+		card = oldcard;
+	}
+
+	/*
+	 * Switch to high-speed (if supported).
+	 */
+	err = sdio_enable_hs(card);
+	if (err)
+		goto remove;
+
+	/*
+	 * Change to the card's maximum speed.
+	 */
+	if (mmc_card_highspeed(card)) {
+		/*
+		 * The SDIO specification doesn't mention how
+		 * the CIS transfer speed register relates to
+		 * high-speed, but it seems that 50 MHz is
+		 * mandatory.
+		 */
+		mmc_set_clock(host, 50000000);
+	} else {
+		mmc_set_clock(host, card->cis.max_dtr);
+	}
+
+	/*
+	 * Switch to wider bus (if supported).
+	 */
+	err = sdio_enable_wide(card);
+	if (err)
+		goto remove;
+
+	if (!oldcard)
+		host->card = card;
+	return 0;
+
+remove:
+	if (!oldcard)
+		mmc_remove_card(card);
+
+err:
+	return err;
+}
+
+/*
  * Host is being removed. Free up the current card.
  */
 static void mmc_sdio_remove(struct mmc_host *host)
 <at>  <at>  -243,10 +371,74  <at>  <at>  static void mmc_sdio_detect(struct mmc_host *host)
 	}
 }

+/*
+ * SDIO suspend.  We need to suspend all functions separately.
+ * Therefore all registered functions must have drivers with suspend
+ * and resume methods.  Failing that we simply remove the whole card.
+ */
+static void mmc_sdio_suspend(struct mmc_host *host)
+{
+	int i;
+
+	/* make sure all registered functions can suspend/resume */
+	for (i = 0; i < host->card->sdio_funcs; i++) {
+		struct sdio_func *func = host->card->sdio_func[i];
+		if (func && sdio_func_present(func) && func->dev.driver) {
+			struct dev_pm_ops *pmops = func->dev.driver->pm;
+			if (!pmops || !pmops->suspend || !pmops->resume) {
+				/* just remove the entire card in that case */
+				mmc_sdio_remove(host);
+				mmc_claim_host(host);
+				mmc_detach_bus(host);
+				mmc_release_host(host);
+				return;
+			}
+		}
+	}
+
+	/* now suspend them */
+	for (i = 0; i < host->card->sdio_funcs; i++) {
+		struct sdio_func *func = host->card->sdio_func[i];
+		if (func && sdio_func_present(func) && func->dev.driver) {
+			struct dev_pm_ops *pmops = func->dev.driver->pm;
+			pmops->suspend(&func->dev);
+		}
+	}
+}
+
+static void mmc_sdio_resume(struct mmc_host *host)
+{
+	int i, err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+	err = mmc_sdio_init_card(host, host->ocr, host->card);
+	mmc_release_host(host);
+	if (err) {
+		mmc_sdio_remove(host);
+		mmc_claim_host(host);
+		mmc_detach_bus(host);
+		mmc_release_host(host);
+		return;
+	}
+
+	/* resume all functions */
+	for (i = 0; i < host->card->sdio_funcs; i++) {
+		struct sdio_func *func = host->card->sdio_func[i];
+		if (func && sdio_func_present(func) && func->dev.driver) {
+			struct dev_pm_ops *pmops = func->dev.driver->pm;
+			pmops->resume(&func->dev);
+		}
+	}
+}

 static const struct mmc_bus_ops mmc_sdio_ops = {
 	.remove = mmc_sdio_remove,
 	.detect = mmc_sdio_detect,
+	.suspend = mmc_sdio_suspend,
+	.resume = mmc_sdio_resume,
 };

 
 <at>  <at>  -293,103 +485,18  <at>  <at>  int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
 	}

 	/*
-	 * Inform the card of the voltage
+	 * Detect and init the card.
 	 */
-	err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+	err = mmc_sdio_init_card(host, host->ocr, NULL);
 	if (err)
 		goto err;
-
-	/*
-	 * For SPI, enable CRC as appropriate.
-	 */
-	if (mmc_host_is_spi(host)) {
-		err = mmc_spi_set_crc(host, use_spi_crc);
-		if (err)
-			goto err;
-	}
+	card = host->card;

 	/*
 	 * The number of functions on the card is encoded inside
 	 * the ocr.
 	 */
-	funcs = (ocr & 0x70000000) >> 28;
-
-	/*
-	 * Allocate card structure.
-	 */
-	card = mmc_alloc_card(host, NULL);
-	if (IS_ERR(card)) {
-		err = PTR_ERR(card);
-		goto err;
-	}
-
-	card->type = MMC_TYPE_SDIO;
-	card->sdio_funcs = funcs;
-
-	host->card = card;
-
-	/*
-	 * For native busses:  set card RCA and quit open drain mode.
-	 */
-	if (!mmc_host_is_spi(host)) {
-		err = mmc_send_relative_addr(host, &card->rca);
-		if (err)
-			goto remove;
-
-		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
-	}
-
-	/*
-	 * Select card, as all following commands rely on that.
-	 */
-	if (!mmc_host_is_spi(host)) {
-		err = mmc_select_card(card);
-		if (err)
-			goto remove;
-	}
-
-	/*
-	 * Read the common registers.
-	 */
-	err = sdio_read_cccr(card);
-	if (err)
-		goto remove;
-
-	/*
-	 * Read the common CIS tuples.
-	 */
-	err = sdio_read_common_cis(card);
-	if (err)
-		goto remove;
-
-	/*
-	 * Switch to high-speed (if supported).
-	 */
-	err = sdio_enable_hs(card);
-	if (err)
-		goto remove;
-
-	/*
-	 * Change to the card's maximum speed.
-	 */
-	if (mmc_card_highspeed(card)) {
-		/*
-		 * The SDIO specification doesn't mention how
-		 * the CIS transfer speed register relates to
-		 * high-speed, but it seems that 50 MHz is
-		 * mandatory.
-		 */
-		mmc_set_clock(host, 50000000);
-	} else {
-		mmc_set_clock(host, card->cis.max_dtr);
-	}
-
-	/*
-	 * Switch to wider bus (if supported).
-	 */
-	err = sdio_enable_wide(card);
-	if (err)
-		goto remove;
+	card->sdio_funcs = funcs = (ocr & 0x70000000) >> 28;

 	/*
 	 * Initialize (but don't add) all present functions.
--

-- 
1.6.4.1.315.g5106d.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo <at> vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Nicolas Pitre | 2 Sep 20:37 2009

[PATCH 2/4] [MMC] propagate error codes back from bus drivers' suspend/resume methods

Especially for SDIO drivers which may have special conditions/errors
to report, it is a good thing to relay the returned error code back to
upper layers.

This also allows for the rationalization of the resume path where code
to "remove" a no-longer-existing or replaced card was duplicated into
the MMC, SD and SDIO bus drivers.

In the SDIO case, if a function suspend method returns an error, then
all previously suspended functions are resumed and the error returned.
An exception is made for -ENOSYS which the core interprets as "we don't
support suspend so just kick the card out for suspend and return success".

Signed-off-by: Nicolas Pitre <nico <at> marvell.com>
---
 drivers/mmc/core/core.c |   35 ++++++++++++++++++++++++++++-------
 drivers/mmc/core/core.h |    4 ++--
 drivers/mmc/core/mmc.c  |   15 +++++----------
 drivers/mmc/core/sd.c   |   15 +++++----------
 drivers/mmc/core/sdio.c |   41 +++++++++++++++++------------------------
 5 files changed, 57 insertions(+), 53 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2649117..2853f58 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
 <at>  <at>  -958,27 +958,34  <at>  <at>  void mmc_stop_host(struct mmc_host *host)
  */
 int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
 {
+	int err = 0;
+
 	cancel_delayed_work(&host->detect);
 	mmc_flush_scheduled_work();

 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
 		if (host->bus_ops->suspend)
-			host->bus_ops->suspend(host);
-		if (!host->bus_ops->resume) {
+			err = host->bus_ops->suspend(host);
+		if (err == -ENOSYS || !host->bus_ops->resume) {
+			/*
+			 * We simply "remove" the card in this case.
+			 * It will be redetected on resume.
+			 */
 			if (host->bus_ops->remove)
 				host->bus_ops->remove(host);
-
 			mmc_claim_host(host);
 			mmc_detach_bus(host);
 			mmc_release_host(host);
+			err = 0;
 		}
 	}
 	mmc_bus_put(host);

-	mmc_power_off(host);
+	if (!err)
+		mmc_power_off(host);

-	return 0;
+	return err;
 }

 EXPORT_SYMBOL(mmc_suspend_host);
 <at>  <at>  -989,12 +996,26  <at>  <at>  EXPORT_SYMBOL(mmc_suspend_host);
  */
 int mmc_resume_host(struct mmc_host *host)
 {
+	int err = 0;
+
 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
 		mmc_power_up(host);
 		mmc_select_voltage(host, host->ocr);
 		BUG_ON(!host->bus_ops->resume);
-		host->bus_ops->resume(host);
+		err = host->bus_ops->resume(host);
+		if (err) {
+			printk(KERN_WARNING "%s: error %d during resume "
+					    "(card was removed?)\n",
+					    mmc_hostname(host), err);
+			if (host->bus_ops->remove)
+				host->bus_ops->remove(host);
+			mmc_claim_host(host);
+			mmc_detach_bus(host);
+			mmc_release_host(host);
+			/* no need to bother upper layers */
+			err = 0;
+		}
 	}
 	mmc_bus_put(host);

 <at>  <at>  -1004,7 +1025,7  <at>  <at>  int mmc_resume_host(struct mmc_host *host)
 	 */
 	mmc_detect_change(host, 1);

-	return 0;
+	return err;
 }

 EXPORT_SYMBOL(mmc_resume_host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index c819eff..767d212 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
 <at>  <at>  -18,8 +18,8  <at>  <at> 
 struct mmc_bus_ops {
 	void (*remove)(struct mmc_host *);
 	void (*detect)(struct mmc_host *);
-	void (*suspend)(struct mmc_host *);
-	void (*resume)(struct mmc_host *);
+	int (*suspend)(struct mmc_host *);
+	int (*resume)(struct mmc_host *);
 };

 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 06084db..188ae06 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
 <at>  <at>  -512,7 +512,7  <at>  <at>  static void mmc_detect(struct mmc_host *host)
 /*
  * Suspend callback from host.
  */
-static void mmc_suspend(struct mmc_host *host)
+static int mmc_suspend(struct mmc_host *host)
 {
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 <at>  <at>  -522,6 +522,8  <at>  <at>  static void mmc_suspend(struct mmc_host *host)
 		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
+
+	return 0;
 }

 /*
 <at>  <at>  -530,7 +532,7  <at>  <at>  static void mmc_suspend(struct mmc_host *host)
  * This function tries to determine if the same card is still present
  * and, if so, restore all state to it.
  */
-static void mmc_resume(struct mmc_host *host)
+static int mmc_resume(struct mmc_host *host)
 {
 	int err;

 <at>  <at>  -541,14 +543,7  <at>  <at>  static void mmc_resume(struct mmc_host *host)
 	err = mmc_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);

-	if (err) {
-		mmc_remove(host);
-
-		mmc_claim_host(host);
-		mmc_detach_bus(host);
-		mmc_release_host(host);
-	}
-
+	return err;
 }

 #else
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index cd81c39..4539a46 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
 <at>  <at>  -566,7 +566,7  <at>  <at>  static void mmc_sd_detect(struct mmc_host *host)
 /*
  * Suspend callback from host.
  */
-static void mmc_sd_suspend(struct mmc_host *host)
+static int mmc_sd_suspend(struct mmc_host *host)
 {
 	BUG_ON(!host);
 	BUG_ON(!host->card);
 <at>  <at>  -576,6 +576,8  <at>  <at>  static void mmc_sd_suspend(struct mmc_host *host)
 		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
+
+	return 0;
 }

 /*
 <at>  <at>  -584,7 +586,7  <at>  <at>  static void mmc_sd_suspend(struct mmc_host *host)
  * This function tries to determine if the same card is still present
  * and, if so, restore all state to it.
  */
-static void mmc_sd_resume(struct mmc_host *host)
+static int mmc_sd_resume(struct mmc_host *host)
 {
 	int err;

 <at>  <at>  -595,14 +597,7  <at>  <at>  static void mmc_sd_resume(struct mmc_host *host)
 	err = mmc_sd_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);

-	if (err) {
-		mmc_sd_remove(host);
-
-		mmc_claim_host(host);
-		mmc_detach_bus(host);
-		mmc_release_host(host);
-	}
-
+	return err;
 }

 #else
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4c21b74..d592423 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
 <at>  <at>  -376,37 +376,35  <at>  <at>  static void mmc_sdio_detect(struct mmc_host *host)
  * Therefore all registered functions must have drivers with suspend
  * and resume methods.  Failing that we simply remove the whole card.
  */
-static void mmc_sdio_suspend(struct mmc_host *host)
+static int mmc_sdio_suspend(struct mmc_host *host)
 {
-	int i;
+	int i, err = 0;

-	/* make sure all registered functions can suspend/resume */
 	for (i = 0; i < host->card->sdio_funcs; i++) {
 		struct sdio_func *func = host->card->sdio_func[i];
 		if (func && sdio_func_present(func) && func->dev.driver) {
 			struct dev_pm_ops *pmops = func->dev.driver->pm;
 			if (!pmops || !pmops->suspend || !pmops->resume) {
-				/* just remove the entire card in that case */
-				mmc_sdio_remove(host);
-				mmc_claim_host(host);
-				mmc_detach_bus(host);
-				mmc_release_host(host);
-				return;
-			}
+				/* force removal of entire card in that case */
+				err = -ENOSYS;
+			} else
+				err = pmops->suspend(&func->dev);
+			if (err)
+				break;
 		}
 	}
-
-	/* now suspend them */
-	for (i = 0; i < host->card->sdio_funcs; i++) {
+	while (err && --i >= 0) {
 		struct sdio_func *func = host->card->sdio_func[i];
 		if (func && sdio_func_present(func) && func->dev.driver) {
 			struct dev_pm_ops *pmops = func->dev.driver->pm;
-			pmops->suspend(&func->dev);
+			pmops->resume(&func->dev);
 		}
 	}
+
+	return err;
 }

-static void mmc_sdio_resume(struct mmc_host *host)
+static int mmc_sdio_resume(struct mmc_host *host)
 {
 	int i, err;

 <at>  <at>  -416,22 +414,17  <at>  <at>  static void mmc_sdio_resume(struct mmc_host *host)
 	mmc_claim_host(host);
 	err = mmc_sdio_init_card(host, host->ocr, host->card);
 	mmc_release_host(host);
-	if (err) {
-		mmc_sdio_remove(host);
-		mmc_claim_host(host);
-		mmc_detach_bus(host);
-		mmc_release_host(host);
-		return;
-	}

 	/* resume all functions */
-	for (i = 0; i < host->card->sdio_funcs; i++) {
+	for (i = 0; !err && i < host->card->sdio_funcs; i++) {
 		struct sdio_func *func = host->card->sdio_func[i];
 		if (func && sdio_func_present(func) && func->dev.driver) {
 			struct dev_pm_ops *pmops = func->dev.driver->pm;
-			pmops->resume(&func->dev);
+			err = pmops->resume(&func->dev);
 		}
 	}
+
+	return err;
 }

 static const struct mmc_bus_ops mmc_sdio_ops = {
--

-- 
1.6.4.1.315.g5106d.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo <at> vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Gmane