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