Message ID | 4287858.bFmM5lK9H6@aspire.rjw.lan (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
On Tue, Feb 20, 2018 at 12:47:27PM +0100, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> > > There is a problem with PCMCIA system resume callbacks with respect > to suspend-to-idle in which the ->suspend_noirq() callback may be > invoked after the ->resume_noirq() one without resuming the system > entirely in some cases. This doesn't work for PCMCIA because of > the lack of symmetry between its system suspend and system resume > "noirq" callbacks. > > The system resume handling in PCMCIA is split between > socket_early_resume() and socket_late_resume() which are called in > different phases of system resume and both need to run for > socket_suspend() (invoked by the system suspend "noirq" callback) > to work. Specifically, socket_suspend() returns an error when > called after socket_early_resume() without socket_late_resume(), > so if the suspend-to-idle core detects a spurious wakeup event and > attempts to put the system back to sleep, that is aborted by the > error coming from socket_suspend(). > > This design doesn't follow the power management documentation > stating that the "noirq" resume callback is expected to reverse > the changes made by the "noirq" suspend one. Moreover, I don't see > a reason for splitting the PCMCIA socket system resume handling this > way Unless I am mistaken, this split was introduced by commit 9905d1b411946 . So we should take into account the reasons stated in that commit message. Thanks, Dominik
On Tue, Feb 20, 2018 at 10:38 PM, Dominik Brodowski <linux@dominikbrodowski.net> wrote: > On Tue, Feb 20, 2018 at 12:47:27PM +0100, Rafael J. Wysocki wrote: >> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com> >> >> There is a problem with PCMCIA system resume callbacks with respect >> to suspend-to-idle in which the ->suspend_noirq() callback may be >> invoked after the ->resume_noirq() one without resuming the system >> entirely in some cases. This doesn't work for PCMCIA because of >> the lack of symmetry between its system suspend and system resume >> "noirq" callbacks. >> >> The system resume handling in PCMCIA is split between >> socket_early_resume() and socket_late_resume() which are called in >> different phases of system resume and both need to run for >> socket_suspend() (invoked by the system suspend "noirq" callback) >> to work. Specifically, socket_suspend() returns an error when >> called after socket_early_resume() without socket_late_resume(), >> so if the suspend-to-idle core detects a spurious wakeup event and >> attempts to put the system back to sleep, that is aborted by the >> error coming from socket_suspend(). >> >> This design doesn't follow the power management documentation >> stating that the "noirq" resume callback is expected to reverse >> the changes made by the "noirq" suspend one. Moreover, I don't see >> a reason for splitting the PCMCIA socket system resume handling this >> way > > Unless I am mistaken, this split was introduced by commit > 9905d1b411946 . So we should take into account the reasons stated > in that commit message. Well, I should have done more research, thanks for reminding me about that. I guess I'll need to add one more state flag, then.
Index: linux-pm/drivers/pcmcia/cs.c =================================================================== --- linux-pm.orig/drivers/pcmcia/cs.c +++ linux-pm/drivers/pcmcia/cs.c @@ -467,23 +467,17 @@ static int socket_suspend(struct pcmcia_ return 0; } -static int socket_early_resume(struct pcmcia_socket *skt) +static int __socket_resume(struct pcmcia_socket *skt) { + int ret = 0; + mutex_lock(&skt->ops_mutex); 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); - mutex_unlock(&skt->ops_mutex); - return 0; -} -static int socket_late_resume(struct pcmcia_socket *skt) -{ - int ret = 0; - - mutex_lock(&skt->ops_mutex); skt->state &= ~SOCKET_SUSPEND; mutex_unlock(&skt->ops_mutex); @@ -546,8 +540,7 @@ static int socket_resume(struct pcmcia_s if (!(skt->state & SOCKET_SUSPEND)) return -EBUSY; - socket_early_resume(skt); - err = socket_late_resume(skt); + err = __socket_resume(skt); if (!err) err = socket_complete_resume(skt); return err; @@ -853,12 +846,7 @@ static int pcmcia_socket_dev_suspend_noi static int pcmcia_socket_dev_resume_noirq(struct device *dev) { - return __pcmcia_pm_op(dev, socket_early_resume); -} - -static int __used pcmcia_socket_dev_resume(struct device *dev) -{ - return __pcmcia_pm_op(dev, socket_late_resume); + return __pcmcia_pm_op(dev, __socket_resume); } static void __used pcmcia_socket_dev_complete(struct device *dev) @@ -868,10 +856,6 @@ static void __used pcmcia_socket_dev_com } static const struct dev_pm_ops pcmcia_socket_pm_ops = { - /* dev_resume may be called with IRQs enabled */ - SET_SYSTEM_SLEEP_PM_OPS(NULL, - pcmcia_socket_dev_resume) - /* late suspend must be called with IRQs disabled */ .suspend_noirq = pcmcia_socket_dev_suspend_noirq, .freeze_noirq = pcmcia_socket_dev_suspend_noirq,