PM / yenta: Split resume into early and late parts (rev. 4)

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 <rjw@sisk.pl>
Acked-by: Dominik Brodowski <linux@dominikbrodowski.net>
Reported-by: Stephen J. Gowdy <gowdy@cern.ch>
Tested-by: Jose Marino <braket@hotmail.com>

+59 -28
+44 -27
drivers/pcmcia/cs.c
··· 98 * These functions check for the appropriate struct pcmcia_soket arrays, 99 * and pass them to the low-level functions pcmcia_{suspend,resume}_socket 100 */ 101 static int socket_resume(struct pcmcia_socket *skt); 102 static int socket_suspend(struct pcmcia_socket *skt); 103 104 - int pcmcia_socket_dev_suspend(struct device *dev) 105 { 106 struct pcmcia_socket *socket; 107 ··· 113 if (socket->dev.parent != dev) 114 continue; 115 mutex_lock(&socket->skt_mutex); 116 - socket_suspend(socket); 117 mutex_unlock(&socket->skt_mutex); 118 } 119 up_read(&pcmcia_socket_list_rwsem); 120 121 return 0; 122 } 123 EXPORT_SYMBOL(pcmcia_socket_dev_suspend); 124 125 int pcmcia_socket_dev_resume(struct device *dev) 126 { 127 - struct pcmcia_socket *socket; 128 - 129 - down_read(&pcmcia_socket_list_rwsem); 130 - list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { 131 - if (socket->dev.parent != dev) 132 - continue; 133 - mutex_lock(&socket->skt_mutex); 134 - socket_resume(socket); 135 - mutex_unlock(&socket->skt_mutex); 136 - } 137 - up_read(&pcmcia_socket_list_rwsem); 138 - 139 return 0; 140 } 141 EXPORT_SYMBOL(pcmcia_socket_dev_resume); ··· 554 return 0; 555 } 556 557 - /* 558 - * Resume a socket. If a card is present, verify its CIS against 559 - * our cached copy. If they are different, the card has been 560 - * replaced, and we need to tell the drivers. 561 - */ 562 - static int socket_resume(struct pcmcia_socket *skt) 563 { 564 - int ret; 565 - 566 - if (!(skt->state & SOCKET_SUSPEND)) 567 - return -EBUSY; 568 - 569 skt->socket = dead_socket; 570 skt->ops->init(skt); 571 skt->ops->set_socket(skt, &skt->socket); 572 573 if (!(skt->state & SOCKET_PRESENT)) { 574 skt->state &= ~SOCKET_SUSPEND; 575 return socket_insert(skt); 576 } 577 578 - ret = socket_setup(skt, resume_delay); 579 - if (ret == 0) { 580 /* 581 * FIXME: need a better check here for cardbus cards. 582 */ ··· 597 skt->state &= ~SOCKET_SUSPEND; 598 599 return 0; 600 } 601 602 static void socket_remove(struct pcmcia_socket *skt)
··· 98 * These functions check for the appropriate struct pcmcia_soket arrays, 99 * and pass them to the low-level functions pcmcia_{suspend,resume}_socket 100 */ 101 + static int socket_early_resume(struct pcmcia_socket *skt); 102 + static int socket_late_resume(struct pcmcia_socket *skt); 103 static int socket_resume(struct pcmcia_socket *skt); 104 static int socket_suspend(struct pcmcia_socket *skt); 105 106 + static void pcmcia_socket_dev_run(struct device *dev, 107 + int (*cb)(struct pcmcia_socket *)) 108 { 109 struct pcmcia_socket *socket; 110 ··· 110 if (socket->dev.parent != dev) 111 continue; 112 mutex_lock(&socket->skt_mutex); 113 + cb(socket); 114 mutex_unlock(&socket->skt_mutex); 115 } 116 up_read(&pcmcia_socket_list_rwsem); 117 + } 118 119 + int pcmcia_socket_dev_suspend(struct device *dev) 120 + { 121 + pcmcia_socket_dev_run(dev, socket_suspend); 122 return 0; 123 } 124 EXPORT_SYMBOL(pcmcia_socket_dev_suspend); 125 126 + void pcmcia_socket_dev_early_resume(struct device *dev) 127 + { 128 + pcmcia_socket_dev_run(dev, socket_early_resume); 129 + } 130 + EXPORT_SYMBOL(pcmcia_socket_dev_early_resume); 131 + 132 + void pcmcia_socket_dev_late_resume(struct device *dev) 133 + { 134 + pcmcia_socket_dev_run(dev, socket_late_resume); 135 + } 136 + EXPORT_SYMBOL(pcmcia_socket_dev_late_resume); 137 + 138 int pcmcia_socket_dev_resume(struct device *dev) 139 { 140 + pcmcia_socket_dev_run(dev, socket_resume); 141 return 0; 142 } 143 EXPORT_SYMBOL(pcmcia_socket_dev_resume); ··· 546 return 0; 547 } 548 549 + static int socket_early_resume(struct pcmcia_socket *skt) 550 { 551 skt->socket = dead_socket; 552 skt->ops->init(skt); 553 skt->ops->set_socket(skt, &skt->socket); 554 + if (skt->state & SOCKET_PRESENT) 555 + skt->resume_status = socket_setup(skt, resume_delay); 556 + return 0; 557 + } 558 559 + static int socket_late_resume(struct pcmcia_socket *skt) 560 + { 561 if (!(skt->state & SOCKET_PRESENT)) { 562 skt->state &= ~SOCKET_SUSPEND; 563 return socket_insert(skt); 564 } 565 566 + if (skt->resume_status == 0) { 567 /* 568 * FIXME: need a better check here for cardbus cards. 569 */ ··· 594 skt->state &= ~SOCKET_SUSPEND; 595 596 return 0; 597 + } 598 + 599 + /* 600 + * Resume a socket. If a card is present, verify its CIS against 601 + * our cached copy. If they are different, the card has been 602 + * replaced, and we need to tell the drivers. 603 + */ 604 + static int socket_resume(struct pcmcia_socket *skt) 605 + { 606 + if (!(skt->state & SOCKET_SUSPEND)) 607 + return -EBUSY; 608 + 609 + socket_early_resume(skt); 610 + return socket_late_resume(skt); 611 } 612 613 static void socket_remove(struct pcmcia_socket *skt)
+11 -1
drivers/pcmcia/yenta_socket.c
··· 1275 if (socket->type && socket->type->restore_state) 1276 socket->type->restore_state(socket); 1277 1278 - return pcmcia_socket_dev_resume(dev); 1279 } 1280 1281 static struct dev_pm_ops yenta_pm_ops = { 1282 .suspend_noirq = yenta_dev_suspend_noirq, 1283 .resume_noirq = yenta_dev_resume_noirq, 1284 .freeze_noirq = yenta_dev_suspend_noirq, 1285 .thaw_noirq = yenta_dev_resume_noirq, 1286 .poweroff_noirq = yenta_dev_suspend_noirq, 1287 .restore_noirq = yenta_dev_resume_noirq, 1288 }; 1289 1290 #define YENTA_PM_OPS (&yenta_pm_ops)
··· 1275 if (socket->type && socket->type->restore_state) 1276 socket->type->restore_state(socket); 1277 1278 + pcmcia_socket_dev_early_resume(dev); 1279 + return 0; 1280 + } 1281 + 1282 + static int yenta_dev_resume(struct device *dev) 1283 + { 1284 + pcmcia_socket_dev_late_resume(dev); 1285 + return 0; 1286 } 1287 1288 static struct dev_pm_ops yenta_pm_ops = { 1289 .suspend_noirq = yenta_dev_suspend_noirq, 1290 .resume_noirq = yenta_dev_resume_noirq, 1291 + .resume = yenta_dev_resume, 1292 .freeze_noirq = yenta_dev_suspend_noirq, 1293 .thaw_noirq = yenta_dev_resume_noirq, 1294 + .thaw = yenta_dev_resume, 1295 .poweroff_noirq = yenta_dev_suspend_noirq, 1296 .restore_noirq = yenta_dev_resume_noirq, 1297 + .restore = yenta_dev_resume, 1298 }; 1299 1300 #define YENTA_PM_OPS (&yenta_pm_ops)
+4
include/pcmcia/ss.h
··· 262 struct device dev; 263 /* data internal to the socket driver */ 264 void *driver_data; 265 }; 266 267 ··· 282 283 /* socket drivers are expected to use these callbacks in their .drv struct */ 284 extern int pcmcia_socket_dev_suspend(struct device *dev); 285 extern int pcmcia_socket_dev_resume(struct device *dev); 286 287 /* socket drivers use this callback in their IRQ handler */
··· 262 struct device dev; 263 /* data internal to the socket driver */ 264 void *driver_data; 265 + /* status of the card during resume from a system sleep state */ 266 + int resume_status; 267 }; 268 269 ··· 280 281 /* socket drivers are expected to use these callbacks in their .drv struct */ 282 extern int pcmcia_socket_dev_suspend(struct device *dev); 283 + extern void pcmcia_socket_dev_early_resume(struct device *dev); 284 + extern void pcmcia_socket_dev_late_resume(struct device *dev); 285 extern int pcmcia_socket_dev_resume(struct device *dev); 286 287 /* socket drivers use this callback in their IRQ handler */