Commit 42b5dd51 authored by Christian Lamparter's avatar Christian Lamparter Committed by Linus Torvalds

pcmcia: move unbind/rebind into dev_pm_ops.complete

Move the device rebind procedures for cardbus devices from the pm.resume
into the pm.complete callback.

The reason for moving the code is: "[...] The PM code needs to send
suspend and resume messages to every device in the right order, and it
can't do that if new devices are being added at the same time.  [...]"

However the situation really isn't quite that rigid.  In particular,
adding new children during a resume callback shouldn't cause much of
problem because the children don't need to be resumed anyway (since they
were never suspended).  On the other hand, if you do it you will get a
dev_warn() from the PM core, something like 'parent should not be
sleeping'.

Still, it is considered bad form and should be avoided if possible."

(Alan Stern's full comment about the topic can
be found here: <https://lkml.org/lkml/2012/7/10/254>)
Signed-off-by: default avatarChristian Lamparter <chunkeey@googlemail.com>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Greg KH <greg@kroah.com>
Acked-by: default avatar"Rafael J. Wysocki" <rjw@sisk.pl>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ddfe9b35
...@@ -484,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt) ...@@ -484,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt)
static int socket_late_resume(struct pcmcia_socket *skt) static int socket_late_resume(struct pcmcia_socket *skt)
{ {
int ret; int ret = 0;
mutex_lock(&skt->ops_mutex); mutex_lock(&skt->ops_mutex);
skt->state &= ~SOCKET_SUSPEND; skt->state &= ~SOCKET_SUSPEND;
...@@ -511,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt) ...@@ -511,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt)
return socket_insert(skt); return socket_insert(skt);
} }
if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
ret = skt->callback->early_resume(skt);
return ret;
}
/*
* Finalize the resume. In case of a cardbus socket, we have
* to rebind the devices as we can't be certain that it has been
* replaced, or not.
*/
static int socket_complete_resume(struct pcmcia_socket *skt)
{
int ret = 0;
#ifdef CONFIG_CARDBUS #ifdef CONFIG_CARDBUS
if (skt->state & SOCKET_CARDBUS) { if (skt->state & SOCKET_CARDBUS) {
/* We can't be sure the CardBus card is the same /* We can't be sure the CardBus card is the same
* as the one previously inserted. Therefore, remove * as the one previously inserted. Therefore, remove
* and re-add... */ * and re-add... */
cb_free(skt); cb_free(skt);
cb_alloc(skt); ret = cb_alloc(skt);
return 0; if (ret)
cb_free(skt);
} }
#endif #endif
if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) return ret;
skt->callback->early_resume(skt);
return 0;
} }
/* /*
...@@ -533,11 +545,15 @@ static int socket_late_resume(struct pcmcia_socket *skt) ...@@ -533,11 +545,15 @@ static int socket_late_resume(struct pcmcia_socket *skt)
*/ */
static int socket_resume(struct pcmcia_socket *skt) static int socket_resume(struct pcmcia_socket *skt)
{ {
int err;
if (!(skt->state & SOCKET_SUSPEND)) if (!(skt->state & SOCKET_SUSPEND))
return -EBUSY; return -EBUSY;
socket_early_resume(skt); socket_early_resume(skt);
return socket_late_resume(skt); err = socket_late_resume(skt);
if (!err)
err = socket_complete_resume(skt);
return err;
} }
static void socket_remove(struct pcmcia_socket *skt) static void socket_remove(struct pcmcia_socket *skt)
...@@ -848,6 +864,12 @@ static int __used pcmcia_socket_dev_resume(struct device *dev) ...@@ -848,6 +864,12 @@ static int __used pcmcia_socket_dev_resume(struct device *dev)
return __pcmcia_pm_op(dev, socket_late_resume); return __pcmcia_pm_op(dev, socket_late_resume);
} }
static void __used pcmcia_socket_dev_complete(struct device *dev)
{
WARN(__pcmcia_pm_op(dev, socket_complete_resume),
"failed to complete resume");
}
static const struct dev_pm_ops pcmcia_socket_pm_ops = { static const struct dev_pm_ops pcmcia_socket_pm_ops = {
/* dev_resume may be called with IRQs enabled */ /* dev_resume may be called with IRQs enabled */
SET_SYSTEM_SLEEP_PM_OPS(NULL, SET_SYSTEM_SLEEP_PM_OPS(NULL,
...@@ -862,6 +884,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = { ...@@ -862,6 +884,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = {
.resume_noirq = pcmcia_socket_dev_resume_noirq, .resume_noirq = pcmcia_socket_dev_resume_noirq,
.thaw_noirq = pcmcia_socket_dev_resume_noirq, .thaw_noirq = pcmcia_socket_dev_resume_noirq,
.restore_noirq = pcmcia_socket_dev_resume_noirq, .restore_noirq = pcmcia_socket_dev_resume_noirq,
.complete = pcmcia_socket_dev_complete,
}; };
#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment