[kernel] r16365 - in dists/sid/linux-2.6/debian: . patches/bugfix/all patches/debian patches/series

Ben Hutchings benh at alioth.debian.org
Tue Sep 28 01:59:56 UTC 2010


Author: benh
Date: Tue Sep 28 01:59:54 2010
New Revision: 16365

Log:
mmc: fix hangs related to mmc/sd card insert/removal during suspend/resume (Closes: #598147)

Added:
   dists/sid/linux-2.6/debian/patches/bugfix/all/mmc-fix-mmc-sd-hangs-during-suspend-resume.patch
   dists/sid/linux-2.6/debian/patches/debian/mmc-Avoid-ABI-change-from-suspend-fix.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/24

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Tue Sep 28 01:21:38 2010	(r16364)
+++ dists/sid/linux-2.6/debian/changelog	Tue Sep 28 01:59:54 2010	(r16365)
@@ -32,6 +32,8 @@
   * 3c59x: Remove incorrect locking (Closes: #598103)
   * f71882fg: Add support for the f71889fg (Closes: #597820)
   * drm/radeon: Fix regressions introduced in 2.6.34.3 (Closes: #597636)
+  * mmc: fix hangs related to mmc/sd card insert/removal during suspend/resume
+    (Closes: #598147)
 
   [ Martin Michlmayr ]
   * ARM: update mach types.

Added: dists/sid/linux-2.6/debian/patches/bugfix/all/mmc-fix-mmc-sd-hangs-during-suspend-resume.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/mmc-fix-mmc-sd-hangs-during-suspend-resume.patch	Tue Sep 28 01:59:54 2010	(r16365)
@@ -0,0 +1,220 @@
+From 38767952d597b58fb1f15bcb20019c6fe4eecace Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <maximlevitsky at gmail.com>
+Date: Tue, 10 Aug 2010 18:01:41 -0700
+Subject: [PATCH 1/2] mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume
+
+commit 4c2ef25fe0b847d2ae818f74758ddb0be1c27d8e upstream.
+
+If you don't use CONFIG_MMC_UNSAFE_RESUME, as soon as you attempt to
+suspend, the card will be removed, therefore this patch doesn't change the
+behavior of this option.
+
+However the removal will be done by pm notifier, which runs while
+userspace is still not frozen and thus can freely use del_gendisk, without
+the risk of deadlock which would happen otherwise.
+
+Card detect workqueue is now disabled while userspace is frozen, Therefore
+if you do use CONFIG_MMC_UNSAFE_RESUME, and remove the card during
+suspend, the removal will be detected as soon as userspace is unfrozen,
+again at the moment it is safe to call del_gendisk.
+
+Tested with and without CONFIG_MMC_UNSAFE_RESUME with suspend and hibernate.
+
+[akpm at linux-foundation.org: clean up function prototype]
+[akpm at linux-foundation.org: fix CONFIG_PM-n linkage, small cleanups]
+[akpm at linux-foundation.org: coding-style fixes]
+Signed-off-by: Maxim Levitsky <maximlevitsky at gmail.com>
+Cc: David Brownell <david-b at pacbell.net>
+Cc: Alan Stern <stern at rowland.harvard.edu>
+Cc: <linux-mmc at vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
+[bwh: Adjust for 2.6.32]
+---
+ drivers/mmc/core/core.c  |   81 +++++++++++++++++++++++++++++++--------------
+ drivers/mmc/core/host.c  |    4 ++
+ include/linux/mmc/host.h |    3 ++
+ 3 files changed, 63 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index 30acd52..46f6157 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -1057,6 +1057,17 @@ void mmc_rescan(struct work_struct *work)
+ 		container_of(work, struct mmc_host, detect.work);
+ 	u32 ocr;
+ 	int err;
++	unsigned long flags;
++
++	spin_lock_irqsave(&host->lock, flags);
++
++	if (host->rescan_disable) {
++		spin_unlock_irqrestore(&host->lock, flags);
++		return;
++	}
++
++	spin_unlock_irqrestore(&host->lock, flags);
++
+ 
+ 	mmc_bus_get(host);
+ 
+@@ -1263,18 +1274,6 @@ int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+ 	if (host->bus_ops && !host->bus_dead) {
+ 		if (host->bus_ops->suspend)
+ 			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);
+ 
+@@ -1304,28 +1303,60 @@ int mmc_resume_host(struct mmc_host *host)
+ 			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);
+ 
+-	/*
+-	 * We add a slight delay here so that resume can progress
+-	 * in parallel.
+-	 */
+-	mmc_detect_change(host, 1);
+-
+ 	return err;
+ }
+-
+ EXPORT_SYMBOL(mmc_resume_host);
+ 
++/* Do the card removal on suspend if card is assumed removeable
++ * Do that in pm notifier while userspace isn't yet frozen, so we will be able
++   to sync the card.
++*/
++int mmc_pm_notify(struct notifier_block *notify_block,
++					unsigned long mode, void *unused)
++{
++	struct mmc_host *host = container_of(
++		notify_block, struct mmc_host, pm_notify);
++	unsigned long flags;
++
++
++	switch (mode) {
++	case PM_HIBERNATION_PREPARE:
++	case PM_SUSPEND_PREPARE:
++
++		spin_lock_irqsave(&host->lock, flags);
++		host->rescan_disable = 1;
++		spin_unlock_irqrestore(&host->lock, flags);
++		cancel_delayed_work_sync(&host->detect);
++
++		if (!host->bus_ops || host->bus_ops->suspend)
++			break;
++
++		mmc_claim_host(host);
++
++		if (host->bus_ops->remove)
++			host->bus_ops->remove(host);
++
++		mmc_detach_bus(host);
++		mmc_release_host(host);
++		break;
++
++	case PM_POST_SUSPEND:
++	case PM_POST_HIBERNATION:
++
++		spin_lock_irqsave(&host->lock, flags);
++		host->rescan_disable = 0;
++		spin_unlock_irqrestore(&host->lock, flags);
++		mmc_detect_change(host, 0);
++
++	}
++
++	return 0;
++}
+ #endif
+ 
+ static int __init mmc_init(void)
+diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
+index a268d12..b88fc3d 100644
+--- a/drivers/mmc/core/host.c
++++ b/drivers/mmc/core/host.c
+@@ -16,6 +16,7 @@
+ #include <linux/idr.h>
+ #include <linux/pagemap.h>
+ #include <linux/leds.h>
++#include <linux/suspend.h>
+ 
+ #include <linux/mmc/host.h>
+ 
+@@ -84,6 +85,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+ 	init_waitqueue_head(&host->wq);
+ 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+ 	INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
++	host->pm_notify.notifier_call = mmc_pm_notify;
+ 
+ 	/*
+ 	 * By default, hosts do not support SGIO or large requests.
+@@ -132,6 +134,7 @@ int mmc_add_host(struct mmc_host *host)
+ #endif
+ 
+ 	mmc_start_host(host);
++	register_pm_notifier(&host->pm_notify);
+ 
+ 	return 0;
+ }
+@@ -148,6 +151,7 @@ EXPORT_SYMBOL(mmc_add_host);
+  */
+ void mmc_remove_host(struct mmc_host *host)
+ {
++	unregister_pm_notifier(&host->pm_notify);
+ 	mmc_stop_host(host);
+ 
+ #ifdef CONFIG_DEBUG_FS
+diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
+index eaf3636..475ca8a 100644
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -120,6 +120,7 @@ struct mmc_host {
+ 	unsigned int		f_min;
+ 	unsigned int		f_max;
+ 	u32			ocr_avail;
++	struct notifier_block	pm_notify;
+ 
+ #define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
+ #define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
+@@ -177,6 +178,7 @@ struct mmc_host {
+ 
+ 	/* Only used with MMC_CAP_DISABLE */
+ 	int			enabled;	/* host is enabled */
++	int			rescan_disable;	/* disable card detection */
+ 	int			nesting_cnt;	/* "enable" nesting count */
+ 	int			en_dis_recurs;	/* detect recursion */
+ 	unsigned int		disable_delay;	/* disable delay in msecs */
+@@ -249,6 +251,7 @@ int mmc_card_can_sleep(struct mmc_host *host);
+ int mmc_host_enable(struct mmc_host *host);
+ int mmc_host_disable(struct mmc_host *host);
+ int mmc_host_lazy_disable(struct mmc_host *host);
++int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
+ 
+ static inline void mmc_set_disable_delay(struct mmc_host *host,
+ 					 unsigned int disable_delay)
+-- 
+1.7.1
+

Added: dists/sid/linux-2.6/debian/patches/debian/mmc-Avoid-ABI-change-from-suspend-fix.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/debian/mmc-Avoid-ABI-change-from-suspend-fix.patch	Tue Sep 28 01:59:54 2010	(r16365)
@@ -0,0 +1,139 @@
+From 82d9e0d0eb18aced617151c595d3d6c40d8991d5 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Tue, 28 Sep 2010 02:52:32 +0100
+Subject: [PATCH 2/2] mmc: Avoid ABI change from suspend fix
+
+Move rescan_disable flag into the existing bitfield.
+
+Move pm_notify in front of the public struct mmc_host.
+---
+ drivers/mmc/core/core.c  |    4 ++--
+ drivers/mmc/core/host.c  |   16 +++++++++-------
+ include/linux/mmc/host.h |   12 ++++++++++--
+ 3 files changed, 21 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index 46f6157..e5e62be 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -1319,8 +1319,8 @@ EXPORT_SYMBOL(mmc_resume_host);
+ int mmc_pm_notify(struct notifier_block *notify_block,
+ 					unsigned long mode, void *unused)
+ {
+-	struct mmc_host *host = container_of(
+-		notify_block, struct mmc_host, pm_notify);
++	struct mmc_host *host = &container_of(
++		notify_block, struct mmc_host_plus, pm_notify)->host;
+ 	unsigned long flags;
+ 
+ 
+diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
+index b88fc3d..796eea5 100644
+--- a/drivers/mmc/core/host.c
++++ b/drivers/mmc/core/host.c
+@@ -28,7 +28,7 @@
+ static void mmc_host_classdev_release(struct device *dev)
+ {
+ 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+-	kfree(host);
++	kfree(container_of(host, struct mmc_host_plus, host));
+ }
+ 
+ static struct class mmc_host_class = {
+@@ -60,13 +60,15 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+ {
+ 	int err;
+ 	struct mmc_host *host;
++	struct mmc_host_plus *host_plus;
+ 
+ 	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
+ 		return NULL;
+ 
+-	host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+-	if (!host)
++	host_plus = kzalloc(sizeof(struct mmc_host_plus) + extra, GFP_KERNEL);
++	if (!host_plus)
+ 		return NULL;
++	host = &host_plus->host;
+ 
+ 	spin_lock(&mmc_host_lock);
+ 	err = idr_get_new(&mmc_host_idr, host, &host->index);
+@@ -85,7 +87,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+ 	init_waitqueue_head(&host->wq);
+ 	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+ 	INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
+-	host->pm_notify.notifier_call = mmc_pm_notify;
++	host_plus->pm_notify.notifier_call = mmc_pm_notify;
+ 
+ 	/*
+ 	 * By default, hosts do not support SGIO or large requests.
+@@ -102,7 +104,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+ 	return host;
+ 
+ free:
+-	kfree(host);
++	kfree(host_plus);
+ 	return NULL;
+ }
+ 
+@@ -134,7 +136,7 @@ int mmc_add_host(struct mmc_host *host)
+ #endif
+ 
+ 	mmc_start_host(host);
+-	register_pm_notifier(&host->pm_notify);
++	register_pm_notifier(&container_of(host, struct mmc_host_plus, host)->pm_notify);
+ 
+ 	return 0;
+ }
+@@ -151,7 +153,7 @@ EXPORT_SYMBOL(mmc_add_host);
+  */
+ void mmc_remove_host(struct mmc_host *host)
+ {
+-	unregister_pm_notifier(&host->pm_notify);
++	unregister_pm_notifier(&container_of(host, struct mmc_host_plus, host)->pm_notify);
+ 	mmc_stop_host(host);
+ 
+ #ifdef CONFIG_DEBUG_FS
+diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
+index 475ca8a..4f11a2f 100644
+--- a/include/linux/mmc/host.h
++++ b/include/linux/mmc/host.h
+@@ -120,7 +120,6 @@ struct mmc_host {
+ 	unsigned int		f_min;
+ 	unsigned int		f_max;
+ 	u32			ocr_avail;
+-	struct notifier_block	pm_notify;
+ 
+ #define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
+ #define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
+@@ -175,10 +174,12 @@ struct mmc_host {
+ #ifdef CONFIG_MMC_DEBUG
+ 	unsigned int		removed:1;	/* host is being removed */
+ #endif
++#ifndef __GENKSYMS__
++	unsigned int		rescan_disable:1; /* disable card detection */
++#endif
+ 
+ 	/* Only used with MMC_CAP_DISABLE */
+ 	int			enabled;	/* host is enabled */
+-	int			rescan_disable;	/* disable card detection */
+ 	int			nesting_cnt;	/* "enable" nesting count */
+ 	int			en_dis_recurs;	/* detect recursion */
+ 	unsigned int		disable_delay;	/* disable delay in msecs */
+@@ -208,6 +209,13 @@ struct mmc_host {
+ 	unsigned long		private[0] ____cacheline_aligned;
+ };
+ 
++#ifndef __GENKSYMS__
++struct mmc_host_plus {
++	struct notifier_block	pm_notify;
++	struct mmc_host		host;
++};
++#endif
++
+ extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
+ extern int mmc_add_host(struct mmc_host *);
+ extern void mmc_remove_host(struct mmc_host *);
+-- 
+1.7.1
+

Modified: dists/sid/linux-2.6/debian/patches/series/24
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/24	Tue Sep 28 01:21:38 2010	(r16364)
+++ dists/sid/linux-2.6/debian/patches/series/24	Tue Sep 28 01:59:54 2010	(r16365)
@@ -71,3 +71,5 @@
 + features/all/hwmon-f71882fg-Add-support-for-the-f71889fg.patch
 + bugfix/all/drm-radeon-kms-fix-a-regression-on-r7xx-AGP.patch
 + bugfix/all/drm-radeon-kms-fix-segfault-in-r600_ioctl_ioctl_wait_idle.patch
++ bugfix/all/mmc-fix-mmc-sd-hangs-during-suspend-resume.patch
++ debian/mmc-Avoid-ABI-change-from-suspend-fix.patch



More information about the Kernel-svn-changes mailing list