From a4b921d79bab4ed2e1810fd9543f54d103c9d408 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Nov 2009 09:24:07 -0800 Subject: [PATCH] a pcmcia regression fix from Rafael for .31 --- ...ume-into-early-and-late-parts-rev.-4.patch | 207 ++++++++++++++++++ review-2.6.31/series | 1 + 2 files changed, 208 insertions(+) create mode 100644 review-2.6.31/pm-yenta-split-resume-into-early-and-late-parts-rev.-4.patch diff --git a/review-2.6.31/pm-yenta-split-resume-into-early-and-late-parts-rev.-4.patch b/review-2.6.31/pm-yenta-split-resume-into-early-and-late-parts-rev.-4.patch new file mode 100644 index 00000000000..8cb1363f1a6 --- /dev/null +++ b/review-2.6.31/pm-yenta-split-resume-into-early-and-late-parts-rev.-4.patch @@ -0,0 +1,207 @@ +From 9905d1b411946fb3fb228e8c6529fd94afda8a92 Mon Sep 17 00:00:00 2001 +From: Rafael J. Wysocki +Date: Tue, 3 Nov 2009 10:54:58 +0100 +Subject: PM / yenta: Split resume into early and late parts (rev. 4) + +From: Rafael J. Wysocki + +commit 9905d1b411946fb3fb228e8c6529fd94afda8a92 upstream. + +Commit 0c570cdeb8fdfcb354a3e9cd81bfc6a09c19de0c +(PM / yenta: Fix cardbus suspend/resume regression) caused resume to +fail on systems with two CardBus bridges. While the exact nature +of the failure is not known at the moment, it can be worked around by +splitting the yenta resume into an early part, executed during the +early phase of resume, that will only resume the socket and power it +up if there was a card in it during suspend, and a late part, +executed during "regular" resume, that will carry out all of the +remaining yenta resume operations. + +Fixes http://bugzilla.kernel.org/show_bug.cgi?id=14334, which is a +listed regression from 2.6.31. + +Signed-off-by: Rafael J. Wysocki +Acked-by: Dominik Brodowski +Reported-by: Stephen J. Gowdy +Tested-by: Jose Marino +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pcmcia/cs.c | 69 ++++++++++++++++++++++++++---------------- + drivers/pcmcia/yenta_socket.c | 12 ++++++- + include/pcmcia/ss.h | 4 ++ + 3 files changed, 58 insertions(+), 27 deletions(-) + +--- a/drivers/pcmcia/cs.c ++++ b/drivers/pcmcia/cs.c +@@ -98,10 +98,13 @@ EXPORT_SYMBOL(pcmcia_socket_list_rwsem); + * These functions check for the appropriate struct pcmcia_soket arrays, + * and pass them to the low-level functions pcmcia_{suspend,resume}_socket + */ ++static int socket_early_resume(struct pcmcia_socket *skt); ++static int socket_late_resume(struct pcmcia_socket *skt); + static int socket_resume(struct pcmcia_socket *skt); + static int socket_suspend(struct pcmcia_socket *skt); + +-int pcmcia_socket_dev_suspend(struct device *dev) ++static void pcmcia_socket_dev_run(struct device *dev, ++ int (*cb)(struct pcmcia_socket *)) + { + struct pcmcia_socket *socket; + +@@ -110,29 +113,34 @@ int pcmcia_socket_dev_suspend(struct dev + if (socket->dev.parent != dev) + continue; + mutex_lock(&socket->skt_mutex); +- socket_suspend(socket); ++ cb(socket); + mutex_unlock(&socket->skt_mutex); + } + up_read(&pcmcia_socket_list_rwsem); ++} + ++int pcmcia_socket_dev_suspend(struct device *dev) ++{ ++ pcmcia_socket_dev_run(dev, socket_suspend); + return 0; + } + EXPORT_SYMBOL(pcmcia_socket_dev_suspend); + +-int pcmcia_socket_dev_resume(struct device *dev) ++void pcmcia_socket_dev_early_resume(struct device *dev) + { +- struct pcmcia_socket *socket; ++ pcmcia_socket_dev_run(dev, socket_early_resume); ++} ++EXPORT_SYMBOL(pcmcia_socket_dev_early_resume); + +- down_read(&pcmcia_socket_list_rwsem); +- list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { +- if (socket->dev.parent != dev) +- continue; +- mutex_lock(&socket->skt_mutex); +- socket_resume(socket); +- mutex_unlock(&socket->skt_mutex); +- } +- up_read(&pcmcia_socket_list_rwsem); ++void pcmcia_socket_dev_late_resume(struct device *dev) ++{ ++ pcmcia_socket_dev_run(dev, socket_late_resume); ++} ++EXPORT_SYMBOL(pcmcia_socket_dev_late_resume); + ++int pcmcia_socket_dev_resume(struct device *dev) ++{ ++ pcmcia_socket_dev_run(dev, socket_resume); + return 0; + } + EXPORT_SYMBOL(pcmcia_socket_dev_resume); +@@ -546,29 +554,24 @@ static int socket_suspend(struct pcmcia_ + return 0; + } + +-/* +- * Resume a socket. If a card is present, verify its CIS against +- * our cached copy. If they are different, the card has been +- * replaced, and we need to tell the drivers. +- */ +-static int socket_resume(struct pcmcia_socket *skt) ++static int socket_early_resume(struct pcmcia_socket *skt) + { +- int ret; +- +- if (!(skt->state & SOCKET_SUSPEND)) +- return -EBUSY; +- + skt->socket = dead_socket; + skt->ops->init(skt); + skt->ops->set_socket(skt, &skt->socket); ++ if (skt->state & SOCKET_PRESENT) ++ skt->resume_status = socket_setup(skt, resume_delay); ++ return 0; ++} + ++static int socket_late_resume(struct pcmcia_socket *skt) ++{ + if (!(skt->state & SOCKET_PRESENT)) { + skt->state &= ~SOCKET_SUSPEND; + return socket_insert(skt); + } + +- ret = socket_setup(skt, resume_delay); +- if (ret == 0) { ++ if (skt->resume_status == 0) { + /* + * FIXME: need a better check here for cardbus cards. + */ +@@ -596,6 +599,20 @@ static int socket_resume(struct pcmcia_s + return 0; + } + ++/* ++ * Resume a socket. If a card is present, verify its CIS against ++ * our cached copy. If they are different, the card has been ++ * replaced, and we need to tell the drivers. ++ */ ++static int socket_resume(struct pcmcia_socket *skt) ++{ ++ if (!(skt->state & SOCKET_SUSPEND)) ++ return -EBUSY; ++ ++ socket_early_resume(skt); ++ return socket_late_resume(skt); ++} ++ + static void socket_remove(struct pcmcia_socket *skt) + { + dev_printk(KERN_NOTICE, &skt->dev, +--- a/drivers/pcmcia/yenta_socket.c ++++ b/drivers/pcmcia/yenta_socket.c +@@ -1275,16 +1275,26 @@ static int yenta_dev_resume_noirq(struct + if (socket->type && socket->type->restore_state) + socket->type->restore_state(socket); + +- return pcmcia_socket_dev_resume(dev); ++ pcmcia_socket_dev_early_resume(dev); ++ return 0; ++} ++ ++static int yenta_dev_resume(struct device *dev) ++{ ++ pcmcia_socket_dev_late_resume(dev); ++ return 0; + } + + static struct dev_pm_ops yenta_pm_ops = { + .suspend_noirq = yenta_dev_suspend_noirq, + .resume_noirq = yenta_dev_resume_noirq, ++ .resume = yenta_dev_resume, + .freeze_noirq = yenta_dev_suspend_noirq, + .thaw_noirq = yenta_dev_resume_noirq, ++ .thaw = yenta_dev_resume, + .poweroff_noirq = yenta_dev_suspend_noirq, + .restore_noirq = yenta_dev_resume_noirq, ++ .restore = yenta_dev_resume, + }; + + #define YENTA_PM_OPS (¥ta_pm_ops) +--- a/include/pcmcia/ss.h ++++ b/include/pcmcia/ss.h +@@ -262,6 +262,8 @@ struct pcmcia_socket { + struct device dev; + /* data internal to the socket driver */ + void *driver_data; ++ /* status of the card during resume from a system sleep state */ ++ int resume_status; + }; + + +@@ -280,6 +282,8 @@ extern struct pccard_resource_ops pccard + + /* socket drivers are expected to use these callbacks in their .drv struct */ + extern int pcmcia_socket_dev_suspend(struct device *dev); ++extern void pcmcia_socket_dev_early_resume(struct device *dev); ++extern void pcmcia_socket_dev_late_resume(struct device *dev); + extern int pcmcia_socket_dev_resume(struct device *dev); + + /* socket drivers use this callback in their IRQ handler */ diff --git a/review-2.6.31/series b/review-2.6.31/series index 850e3872e7c..0f084aeaecb 100644 --- a/review-2.6.31/series +++ b/review-2.6.31/series @@ -97,3 +97,4 @@ powerpc-pci-fix-regression-in-powerpc-msi-x.patch powerpc-fix-some-late-powermac-g5-with-pcie-ati-graphics.patch sata_via-remove-redundant-device-id-for-via-vt8261.patch pata_via-extend-the-rev_max-for-vt6330.patch +pm-yenta-split-resume-into-early-and-late-parts-rev.-4.patch -- 2.47.3